diff options
| -rw-r--r-- | include/uapi/linux/netfilter_ipv6/ip6t_srh.h | 43 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6t_srh.c | 173 |
2 files changed, 205 insertions, 11 deletions
diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_srh.h b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h index f3cc0ef514a7..54ed83360dac 100644 --- a/include/uapi/linux/netfilter_ipv6/ip6t_srh.h +++ b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h | |||
| @@ -17,7 +17,10 @@ | |||
| 17 | #define IP6T_SRH_LAST_GT 0x0100 | 17 | #define IP6T_SRH_LAST_GT 0x0100 |
| 18 | #define IP6T_SRH_LAST_LT 0x0200 | 18 | #define IP6T_SRH_LAST_LT 0x0200 |
| 19 | #define IP6T_SRH_TAG 0x0400 | 19 | #define IP6T_SRH_TAG 0x0400 |
| 20 | #define IP6T_SRH_MASK 0x07FF | 20 | #define IP6T_SRH_PSID 0x0800 |
| 21 | #define IP6T_SRH_NSID 0x1000 | ||
| 22 | #define IP6T_SRH_LSID 0x2000 | ||
| 23 | #define IP6T_SRH_MASK 0x3FFF | ||
| 21 | 24 | ||
| 22 | /* Values for "mt_invflags" field in struct ip6t_srh */ | 25 | /* Values for "mt_invflags" field in struct ip6t_srh */ |
| 23 | #define IP6T_SRH_INV_NEXTHDR 0x0001 | 26 | #define IP6T_SRH_INV_NEXTHDR 0x0001 |
| @@ -31,7 +34,10 @@ | |||
| 31 | #define IP6T_SRH_INV_LAST_GT 0x0100 | 34 | #define IP6T_SRH_INV_LAST_GT 0x0100 |
| 32 | #define IP6T_SRH_INV_LAST_LT 0x0200 | 35 | #define IP6T_SRH_INV_LAST_LT 0x0200 |
| 33 | #define IP6T_SRH_INV_TAG 0x0400 | 36 | #define IP6T_SRH_INV_TAG 0x0400 |
| 34 | #define IP6T_SRH_INV_MASK 0x07FF | 37 | #define IP6T_SRH_INV_PSID 0x0800 |
| 38 | #define IP6T_SRH_INV_NSID 0x1000 | ||
| 39 | #define IP6T_SRH_INV_LSID 0x2000 | ||
| 40 | #define IP6T_SRH_INV_MASK 0x3FFF | ||
| 35 | 41 | ||
| 36 | /** | 42 | /** |
| 37 | * struct ip6t_srh - SRH match options | 43 | * struct ip6t_srh - SRH match options |
| @@ -54,4 +60,37 @@ struct ip6t_srh { | |||
| 54 | __u16 mt_invflags; | 60 | __u16 mt_invflags; |
| 55 | }; | 61 | }; |
| 56 | 62 | ||
| 63 | /** | ||
| 64 | * struct ip6t_srh1 - SRH match options (revision 1) | ||
| 65 | * @ next_hdr: Next header field of SRH | ||
| 66 | * @ hdr_len: Extension header length field of SRH | ||
| 67 | * @ segs_left: Segments left field of SRH | ||
| 68 | * @ last_entry: Last entry field of SRH | ||
| 69 | * @ tag: Tag field of SRH | ||
| 70 | * @ psid_addr: Address of previous SID in SRH SID list | ||
| 71 | * @ nsid_addr: Address of NEXT SID in SRH SID list | ||
| 72 | * @ lsid_addr: Address of LAST SID in SRH SID list | ||
| 73 | * @ psid_msk: Mask of previous SID in SRH SID list | ||
| 74 | * @ nsid_msk: Mask of next SID in SRH SID list | ||
| 75 | * @ lsid_msk: MAsk of last SID in SRH SID list | ||
| 76 | * @ mt_flags: match options | ||
| 77 | * @ mt_invflags: Invert the sense of match options | ||
| 78 | */ | ||
| 79 | |||
| 80 | struct ip6t_srh1 { | ||
| 81 | __u8 next_hdr; | ||
| 82 | __u8 hdr_len; | ||
| 83 | __u8 segs_left; | ||
| 84 | __u8 last_entry; | ||
| 85 | __u16 tag; | ||
| 86 | struct in6_addr psid_addr; | ||
| 87 | struct in6_addr nsid_addr; | ||
| 88 | struct in6_addr lsid_addr; | ||
| 89 | struct in6_addr psid_msk; | ||
| 90 | struct in6_addr nsid_msk; | ||
| 91 | struct in6_addr lsid_msk; | ||
| 92 | __u16 mt_flags; | ||
| 93 | __u16 mt_invflags; | ||
| 94 | }; | ||
| 95 | |||
| 57 | #endif /*_IP6T_SRH_H*/ | 96 | #endif /*_IP6T_SRH_H*/ |
diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c index 33719d5560c8..1059894a6f4c 100644 --- a/net/ipv6/netfilter/ip6t_srh.c +++ b/net/ipv6/netfilter/ip6t_srh.c | |||
| @@ -117,6 +117,130 @@ static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 117 | return true; | 117 | return true; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 121 | { | ||
| 122 | int hdrlen, psidoff, nsidoff, lsidoff, srhoff = 0; | ||
| 123 | const struct ip6t_srh1 *srhinfo = par->matchinfo; | ||
| 124 | struct in6_addr *psid, *nsid, *lsid; | ||
| 125 | struct in6_addr _psid, _nsid, _lsid; | ||
| 126 | struct ipv6_sr_hdr *srh; | ||
| 127 | struct ipv6_sr_hdr _srh; | ||
| 128 | |||
| 129 | if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0) | ||
| 130 | return false; | ||
| 131 | srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh); | ||
| 132 | if (!srh) | ||
| 133 | return false; | ||
| 134 | |||
| 135 | hdrlen = ipv6_optlen(srh); | ||
| 136 | if (skb->len - srhoff < hdrlen) | ||
| 137 | return false; | ||
| 138 | |||
| 139 | if (srh->type != IPV6_SRCRT_TYPE_4) | ||
| 140 | return false; | ||
| 141 | |||
| 142 | if (srh->segments_left > srh->first_segment) | ||
| 143 | return false; | ||
| 144 | |||
| 145 | /* Next Header matching */ | ||
| 146 | if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR) | ||
| 147 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR, | ||
| 148 | !(srh->nexthdr == srhinfo->next_hdr))) | ||
| 149 | return false; | ||
| 150 | |||
| 151 | /* Header Extension Length matching */ | ||
| 152 | if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ) | ||
| 153 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ, | ||
| 154 | !(srh->hdrlen == srhinfo->hdr_len))) | ||
| 155 | return false; | ||
| 156 | if (srhinfo->mt_flags & IP6T_SRH_LEN_GT) | ||
| 157 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT, | ||
| 158 | !(srh->hdrlen > srhinfo->hdr_len))) | ||
| 159 | return false; | ||
| 160 | if (srhinfo->mt_flags & IP6T_SRH_LEN_LT) | ||
| 161 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT, | ||
| 162 | !(srh->hdrlen < srhinfo->hdr_len))) | ||
| 163 | return false; | ||
| 164 | |||
| 165 | /* Segments Left matching */ | ||
| 166 | if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ) | ||
| 167 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ, | ||
| 168 | !(srh->segments_left == srhinfo->segs_left))) | ||
| 169 | return false; | ||
| 170 | if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT) | ||
| 171 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT, | ||
| 172 | !(srh->segments_left > srhinfo->segs_left))) | ||
| 173 | return false; | ||
| 174 | if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT) | ||
| 175 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT, | ||
| 176 | !(srh->segments_left < srhinfo->segs_left))) | ||
| 177 | return false; | ||
| 178 | |||
| 179 | /** | ||
| 180 | * Last Entry matching | ||
| 181 | * Last_Entry field was introduced in revision 6 of the SRH draft. | ||
| 182 | * It was called First_Segment in the previous revision | ||
| 183 | */ | ||
| 184 | if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ) | ||
| 185 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ, | ||
| 186 | !(srh->first_segment == srhinfo->last_entry))) | ||
| 187 | return false; | ||
| 188 | if (srhinfo->mt_flags & IP6T_SRH_LAST_GT) | ||
| 189 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT, | ||
| 190 | !(srh->first_segment > srhinfo->last_entry))) | ||
| 191 | return false; | ||
| 192 | if (srhinfo->mt_flags & IP6T_SRH_LAST_LT) | ||
| 193 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT, | ||
| 194 | !(srh->first_segment < srhinfo->last_entry))) | ||
| 195 | return false; | ||
| 196 | |||
| 197 | /** | ||
| 198 | * Tag matchig | ||
| 199 | * Tag field was introduced in revision 6 of the SRH draft | ||
| 200 | */ | ||
| 201 | if (srhinfo->mt_flags & IP6T_SRH_TAG) | ||
| 202 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG, | ||
| 203 | !(srh->tag == srhinfo->tag))) | ||
| 204 | return false; | ||
| 205 | |||
| 206 | /* Previous SID matching */ | ||
| 207 | if (srhinfo->mt_flags & IP6T_SRH_PSID) { | ||
| 208 | if (srh->segments_left == srh->first_segment) | ||
| 209 | return false; | ||
| 210 | psidoff = srhoff + sizeof(struct ipv6_sr_hdr) + | ||
| 211 | ((srh->segments_left + 1) * sizeof(struct in6_addr)); | ||
| 212 | psid = skb_header_pointer(skb, psidoff, sizeof(_psid), &_psid); | ||
| 213 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_PSID, | ||
| 214 | ipv6_masked_addr_cmp(psid, &srhinfo->psid_msk, | ||
| 215 | &srhinfo->psid_addr))) | ||
| 216 | return false; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* Next SID matching */ | ||
| 220 | if (srhinfo->mt_flags & IP6T_SRH_NSID) { | ||
| 221 | if (srh->segments_left == 0) | ||
| 222 | return false; | ||
| 223 | nsidoff = srhoff + sizeof(struct ipv6_sr_hdr) + | ||
| 224 | ((srh->segments_left - 1) * sizeof(struct in6_addr)); | ||
| 225 | nsid = skb_header_pointer(skb, nsidoff, sizeof(_nsid), &_nsid); | ||
| 226 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NSID, | ||
| 227 | ipv6_masked_addr_cmp(nsid, &srhinfo->nsid_msk, | ||
| 228 | &srhinfo->nsid_addr))) | ||
| 229 | return false; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* Last SID matching */ | ||
| 233 | if (srhinfo->mt_flags & IP6T_SRH_LSID) { | ||
| 234 | lsidoff = srhoff + sizeof(struct ipv6_sr_hdr); | ||
| 235 | lsid = skb_header_pointer(skb, lsidoff, sizeof(_lsid), &_lsid); | ||
| 236 | if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LSID, | ||
| 237 | ipv6_masked_addr_cmp(lsid, &srhinfo->lsid_msk, | ||
| 238 | &srhinfo->lsid_addr))) | ||
| 239 | return false; | ||
| 240 | } | ||
| 241 | return true; | ||
| 242 | } | ||
| 243 | |||
| 120 | static int srh_mt6_check(const struct xt_mtchk_param *par) | 244 | static int srh_mt6_check(const struct xt_mtchk_param *par) |
| 121 | { | 245 | { |
| 122 | const struct ip6t_srh *srhinfo = par->matchinfo; | 246 | const struct ip6t_srh *srhinfo = par->matchinfo; |
| @@ -136,23 +260,54 @@ static int srh_mt6_check(const struct xt_mtchk_param *par) | |||
| 136 | return 0; | 260 | return 0; |
| 137 | } | 261 | } |
| 138 | 262 | ||
| 139 | static struct xt_match srh_mt6_reg __read_mostly = { | 263 | static int srh1_mt6_check(const struct xt_mtchk_param *par) |
| 140 | .name = "srh", | 264 | { |
| 141 | .family = NFPROTO_IPV6, | 265 | const struct ip6t_srh1 *srhinfo = par->matchinfo; |
| 142 | .match = srh_mt6, | 266 | |
| 143 | .matchsize = sizeof(struct ip6t_srh), | 267 | if (srhinfo->mt_flags & ~IP6T_SRH_MASK) { |
| 144 | .checkentry = srh_mt6_check, | 268 | pr_info_ratelimited("unknown srh match flags %X\n", |
| 145 | .me = THIS_MODULE, | 269 | srhinfo->mt_flags); |
| 270 | return -EINVAL; | ||
| 271 | } | ||
| 272 | |||
| 273 | if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) { | ||
| 274 | pr_info_ratelimited("unknown srh invflags %X\n", | ||
| 275 | srhinfo->mt_invflags); | ||
| 276 | return -EINVAL; | ||
| 277 | } | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | static struct xt_match srh_mt6_reg[] __read_mostly = { | ||
| 283 | { | ||
| 284 | .name = "srh", | ||
| 285 | .revision = 0, | ||
| 286 | .family = NFPROTO_IPV6, | ||
| 287 | .match = srh_mt6, | ||
| 288 | .matchsize = sizeof(struct ip6t_srh), | ||
| 289 | .checkentry = srh_mt6_check, | ||
| 290 | .me = THIS_MODULE, | ||
| 291 | }, | ||
| 292 | { | ||
| 293 | .name = "srh", | ||
| 294 | .revision = 1, | ||
| 295 | .family = NFPROTO_IPV6, | ||
| 296 | .match = srh1_mt6, | ||
| 297 | .matchsize = sizeof(struct ip6t_srh1), | ||
| 298 | .checkentry = srh1_mt6_check, | ||
| 299 | .me = THIS_MODULE, | ||
| 300 | } | ||
| 146 | }; | 301 | }; |
| 147 | 302 | ||
| 148 | static int __init srh_mt6_init(void) | 303 | static int __init srh_mt6_init(void) |
| 149 | { | 304 | { |
| 150 | return xt_register_match(&srh_mt6_reg); | 305 | return xt_register_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg)); |
| 151 | } | 306 | } |
| 152 | 307 | ||
| 153 | static void __exit srh_mt6_exit(void) | 308 | static void __exit srh_mt6_exit(void) |
| 154 | { | 309 | { |
| 155 | xt_unregister_match(&srh_mt6_reg); | 310 | xt_unregister_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg)); |
| 156 | } | 311 | } |
| 157 | 312 | ||
| 158 | module_init(srh_mt6_init); | 313 | module_init(srh_mt6_init); |
