···4747 (nexthdr == IPPROTO_DSTOPTS);4848}49495050-enum {5151- IP6T_FH_F_FRAG = (1 << 0),5252- IP6T_FH_F_AUTH = (1 << 1),5353-};5454-5555-/* find specified header and get offset to it */5656-extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,5757- int target, unsigned short *fragoff, int *fragflg);5858-5950#ifdef CONFIG_COMPAT6051#include <net/compat.h>6152
+9
include/net/ipv6.h
···630630631631extern bool ipv6_ext_hdr(u8 nexthdr);632632633633+enum {634634+ IP6_FH_F_FRAG = (1 << 0),635635+ IP6_FH_F_AUTH = (1 << 1),636636+};637637+638638+/* find specified header and get offset to it */639639+extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,640640+ int target, unsigned short *fragoff, int *fragflg);641641+633642extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);634643635644extern struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
+103
net/ipv6/exthdrs_core.c
···111111 return start;112112}113113EXPORT_SYMBOL(ipv6_skip_exthdr);114114+115115+/*116116+ * find the offset to specified header or the protocol number of last header117117+ * if target < 0. "last header" is transport protocol header, ESP, or118118+ * "No next header".119119+ *120120+ * Note that *offset is used as input/output parameter. an if it is not zero,121121+ * then it must be a valid offset to an inner IPv6 header. This can be used122122+ * to explore inner IPv6 header, eg. ICMPv6 error messages.123123+ *124124+ * If target header is found, its offset is set in *offset and return protocol125125+ * number. Otherwise, return -1.126126+ *127127+ * If the first fragment doesn't contain the final protocol header or128128+ * NEXTHDR_NONE it is considered invalid.129129+ *130130+ * Note that non-1st fragment is special case that "the protocol number131131+ * of last header" is "next header" field in Fragment header. In this case,132132+ * *offset is meaningless and fragment offset is stored in *fragoff if fragoff133133+ * isn't NULL.134134+ *135135+ * if flags is not NULL and it's a fragment, then the frag flag IP6_FH_F_FRAG136136+ * will be set. If it's an AH header, the IP6_FH_F_AUTH flag is set and137137+ * target < 0, then this function will stop at the AH header.138138+ */139139+int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,140140+ int target, unsigned short *fragoff, int *flags)141141+{142142+ unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);143143+ u8 nexthdr = ipv6_hdr(skb)->nexthdr;144144+ unsigned int len;145145+146146+ if (fragoff)147147+ *fragoff = 0;148148+149149+ if (*offset) {150150+ struct ipv6hdr _ip6, *ip6;151151+152152+ ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);153153+ if (!ip6 || (ip6->version != 6)) {154154+ printk(KERN_ERR "IPv6 header not found\n");155155+ return -EBADMSG;156156+ }157157+ start = *offset + sizeof(struct ipv6hdr);158158+ nexthdr = ip6->nexthdr;159159+ }160160+ len = skb->len - start;161161+162162+ while (nexthdr != target) {163163+ struct ipv6_opt_hdr _hdr, *hp;164164+ unsigned int hdrlen;165165+166166+ if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {167167+ if (target < 0)168168+ break;169169+ return -ENOENT;170170+ }171171+172172+ hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);173173+ if (hp == NULL)174174+ return -EBADMSG;175175+ if (nexthdr == NEXTHDR_FRAGMENT) {176176+ unsigned short _frag_off;177177+ __be16 *fp;178178+179179+ if (flags) /* Indicate that this is a fragment */180180+ *flags |= IP6_FH_F_FRAG;181181+ fp = skb_header_pointer(skb,182182+ start+offsetof(struct frag_hdr,183183+ frag_off),184184+ sizeof(_frag_off),185185+ &_frag_off);186186+ if (fp == NULL)187187+ return -EBADMSG;188188+189189+ _frag_off = ntohs(*fp) & ~0x7;190190+ if (_frag_off) {191191+ if (target < 0 &&192192+ ((!ipv6_ext_hdr(hp->nexthdr)) ||193193+ hp->nexthdr == NEXTHDR_NONE)) {194194+ if (fragoff)195195+ *fragoff = _frag_off;196196+ return hp->nexthdr;197197+ }198198+ return -ENOENT;199199+ }200200+ hdrlen = 8;201201+ } else if (nexthdr == NEXTHDR_AUTH) {202202+ if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0))203203+ break;204204+ hdrlen = (hp->hdrlen + 2) << 2;205205+ } else206206+ hdrlen = ipv6_optlen(hp);207207+208208+ nexthdr = hp->nexthdr;209209+ len -= hdrlen;210210+ start += hdrlen;211211+ }212212+213213+ *offset = start;214214+ return nexthdr;215215+}216216+EXPORT_SYMBOL(ipv6_find_hdr);
-103
net/ipv6/netfilter/ip6_tables.c
···22732273 unregister_pernet_subsys(&ip6_tables_net_ops);22742274}2275227522762276-/*22772277- * find the offset to specified header or the protocol number of last header22782278- * if target < 0. "last header" is transport protocol header, ESP, or22792279- * "No next header".22802280- *22812281- * Note that *offset is used as input/output parameter. an if it is not zero,22822282- * then it must be a valid offset to an inner IPv6 header. This can be used22832283- * to explore inner IPv6 header, eg. ICMPv6 error messages.22842284- *22852285- * If target header is found, its offset is set in *offset and return protocol22862286- * number. Otherwise, return -1.22872287- *22882288- * If the first fragment doesn't contain the final protocol header or22892289- * NEXTHDR_NONE it is considered invalid.22902290- *22912291- * Note that non-1st fragment is special case that "the protocol number22922292- * of last header" is "next header" field in Fragment header. In this case,22932293- * *offset is meaningless and fragment offset is stored in *fragoff if fragoff22942294- * isn't NULL.22952295- *22962296- * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG22972297- * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and22982298- * target < 0, then this function will stop at the AH header.22992299- */23002300-int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,23012301- int target, unsigned short *fragoff, int *flags)23022302-{23032303- unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);23042304- u8 nexthdr = ipv6_hdr(skb)->nexthdr;23052305- unsigned int len;23062306-23072307- if (fragoff)23082308- *fragoff = 0;23092309-23102310- if (*offset) {23112311- struct ipv6hdr _ip6, *ip6;23122312-23132313- ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);23142314- if (!ip6 || (ip6->version != 6)) {23152315- printk(KERN_ERR "IPv6 header not found\n");23162316- return -EBADMSG;23172317- }23182318- start = *offset + sizeof(struct ipv6hdr);23192319- nexthdr = ip6->nexthdr;23202320- }23212321- len = skb->len - start;23222322-23232323- while (nexthdr != target) {23242324- struct ipv6_opt_hdr _hdr, *hp;23252325- unsigned int hdrlen;23262326-23272327- if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {23282328- if (target < 0)23292329- break;23302330- return -ENOENT;23312331- }23322332-23332333- hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);23342334- if (hp == NULL)23352335- return -EBADMSG;23362336- if (nexthdr == NEXTHDR_FRAGMENT) {23372337- unsigned short _frag_off;23382338- __be16 *fp;23392339-23402340- if (flags) /* Indicate that this is a fragment */23412341- *flags |= IP6T_FH_F_FRAG;23422342- fp = skb_header_pointer(skb,23432343- start+offsetof(struct frag_hdr,23442344- frag_off),23452345- sizeof(_frag_off),23462346- &_frag_off);23472347- if (fp == NULL)23482348- return -EBADMSG;23492349-23502350- _frag_off = ntohs(*fp) & ~0x7;23512351- if (_frag_off) {23522352- if (target < 0 &&23532353- ((!ipv6_ext_hdr(hp->nexthdr)) ||23542354- hp->nexthdr == NEXTHDR_NONE)) {23552355- if (fragoff)23562356- *fragoff = _frag_off;23572357- return hp->nexthdr;23582358- }23592359- return -ENOENT;23602360- }23612361- hdrlen = 8;23622362- } else if (nexthdr == NEXTHDR_AUTH) {23632363- if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0))23642364- break;23652365- hdrlen = (hp->hdrlen + 2) << 2;23662366- } else23672367- hdrlen = ipv6_optlen(hp);23682368-23692369- nexthdr = hp->nexthdr;23702370- len -= hdrlen;23712371- start += hdrlen;23722372- }23732373-23742374- *offset = start;23752375- return nexthdr;23762376-}23772377-23782276EXPORT_SYMBOL(ip6t_register_table);23792277EXPORT_SYMBOL(ip6t_unregister_table);23802278EXPORT_SYMBOL(ip6t_do_table);23812381-EXPORT_SYMBOL(ipv6_find_hdr);2382227923832280module_init(ip6_tables_init);23842281module_exit(ip6_tables_fini);
+4-4
net/netfilter/xt_HMARK.c
···167167 const struct xt_hmark_info *info)168168{169169 struct ipv6hdr *ip6, _ip6;170170- int flag = IP6T_FH_F_AUTH;170170+ int flag = IP6_FH_F_AUTH;171171 unsigned int nhoff = 0;172172 u16 fragoff = 0;173173 int nexthdr;···177177 if (nexthdr < 0)178178 return 0;179179 /* No need to check for icmp errors on fragments */180180- if ((flag & IP6T_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6))180180+ if ((flag & IP6_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6))181181 goto noicmp;182182 /* Use inner header in case of ICMP errors */183183 if (get_inner6_hdr(skb, &nhoff)) {···185185 if (ip6 == NULL)186186 return -1;187187 /* If AH present, use SPI like in ESP. */188188- flag = IP6T_FH_F_AUTH;188188+ flag = IP6_FH_F_AUTH;189189 nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag);190190 if (nexthdr < 0)191191 return -1;···201201 if (t->proto == IPPROTO_ICMPV6)202202 return 0;203203204204- if (flag & IP6T_FH_F_FRAG)204204+ if (flag & IP6_FH_F_FRAG)205205 return 0;206206207207 hmark_set_tuple_ports(skb, nhoff, t, info);