1 /* 2 * xfrm6_policy.c: based on xfrm4_policy.c 3 * 4 * Authors: 5 * Mitsuru KANDA @USAGI 6 * Kazunori MIYAZAWA @USAGI 7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * IPv6 support 9 * YOSHIFUJI Hideaki 10 * Split up af-specific portion 11 * 12 */ 13 14 #include <linux/err.h> 15 #include <linux/kernel.h> 16 #include <linux/netdevice.h> 17 #include <net/addrconf.h> 18 #include <net/dst.h> 19 #include <net/xfrm.h> 20 #include <net/ip.h> 21 #include <net/ipv6.h> 22 #include <net/ip6_route.h> 23 #include <net/l3mdev.h> 24 #if IS_ENABLED(CONFIG_IPV6_MIP6) 25 #include <net/mip6.h> 26 #endif 27 28 static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, 29 const xfrm_address_t *saddr, 30 const xfrm_address_t *daddr) 31 { 32 struct flowi6 fl6; 33 struct dst_entry *dst; 34 int err; 35 36 memset(&fl6, 0, sizeof(fl6)); 37 fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif); 38 fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF; 39 memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); 40 if (saddr) 41 memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); 42 43 dst = ip6_route_output(net, NULL, &fl6); 44 45 err = dst->error; 46 if (dst->error) { 47 dst_release(dst); 48 dst = ERR_PTR(err); 49 } 50 51 return dst; 52 } 53 54 static int xfrm6_get_saddr(struct net *net, int oif, 55 xfrm_address_t *saddr, xfrm_address_t *daddr) 56 { 57 struct dst_entry *dst; 58 struct net_device *dev; 59 60 dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr); 61 if (IS_ERR(dst)) 62 return -EHOSTUNREACH; 63 64 dev = ip6_dst_idev(dst)->dev; 65 ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6); 66 dst_release(dst); 67 return 0; 68 } 69 70 static int xfrm6_get_tos(const struct flowi *fl) 71 { 72 return 0; 73 } 74 75 static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, 76 int nfheader_len) 77 { 78 if (dst->ops->family == AF_INET6) { 79 struct rt6_info *rt = (struct rt6_info *)dst; 80 path->path_cookie = rt6_get_cookie(rt); 81 } 82 83 path->u.rt6.rt6i_nfheader_len = nfheader_len; 84 85 return 0; 86 } 87 88 static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, 89 const struct flowi *fl) 90 { 91 struct rt6_info *rt = (struct rt6_info *)xdst->route; 92 93 xdst->u.dst.dev = dev; 94 dev_hold(dev); 95 96 xdst->u.rt6.rt6i_idev = in6_dev_get(dev); 97 if (!xdst->u.rt6.rt6i_idev) { 98 dev_put(dev); 99 return -ENODEV; 100 } 101 102 /* Sheit... I remember I did this right. Apparently, 103 * it was magically lost, so this code needs audit */ 104 xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | 105 RTF_LOCAL); 106 xdst->u.rt6.rt6i_metric = rt->rt6i_metric; 107 xdst->u.rt6.rt6i_node = rt->rt6i_node; 108 xdst->route_cookie = rt6_get_cookie(rt); 109 xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; 110 xdst->u.rt6.rt6i_dst = rt->rt6i_dst; 111 xdst->u.rt6.rt6i_src = rt->rt6i_src; 112 113 return 0; 114 } 115 116 static inline void 117 _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) 118 { 119 struct flowi6 *fl6 = &fl->u.ip6; 120 int onlyproto = 0; 121 const struct ipv6hdr *hdr = ipv6_hdr(skb); 122 u16 offset = sizeof(*hdr); 123 struct ipv6_opt_hdr *exthdr; 124 const unsigned char *nh = skb_network_header(skb); 125 u16 nhoff = IP6CB(skb)->nhoff; 126 int oif = 0; 127 u8 nexthdr; 128 129 if (!nhoff) 130 nhoff = offsetof(struct ipv6hdr, nexthdr); 131 132 nexthdr = nh[nhoff]; 133 134 if (skb_dst(skb)) 135 oif = skb_dst(skb)->dev->ifindex; 136 137 memset(fl6, 0, sizeof(struct flowi6)); 138 fl6->flowi6_mark = skb->mark; 139 fl6->flowi6_oif = reverse ? skb->skb_iif : oif; 140 141 fl6->daddr = reverse ? hdr->saddr : hdr->daddr; 142 fl6->saddr = reverse ? hdr->daddr : hdr->saddr; 143 144 while (nh + offset + 1 < skb->data || 145 pskb_may_pull(skb, nh + offset + 1 - skb->data)) { 146 nh = skb_network_header(skb); 147 exthdr = (struct ipv6_opt_hdr *)(nh + offset); 148 149 switch (nexthdr) { 150 case NEXTHDR_FRAGMENT: 151 onlyproto = 1; 152 case NEXTHDR_ROUTING: 153 case NEXTHDR_HOP: 154 case NEXTHDR_DEST: 155 offset += ipv6_optlen(exthdr); 156 nexthdr = exthdr->nexthdr; 157 exthdr = (struct ipv6_opt_hdr *)(nh + offset); 158 break; 159 160 case IPPROTO_UDP: 161 case IPPROTO_UDPLITE: 162 case IPPROTO_TCP: 163 case IPPROTO_SCTP: 164 case IPPROTO_DCCP: 165 if (!onlyproto && (nh + offset + 4 < skb->data || 166 pskb_may_pull(skb, nh + offset + 4 - skb->data))) { 167 __be16 *ports; 168 169 nh = skb_network_header(skb); 170 ports = (__be16 *)(nh + offset); 171 fl6->fl6_sport = ports[!!reverse]; 172 fl6->fl6_dport = ports[!reverse]; 173 } 174 fl6->flowi6_proto = nexthdr; 175 return; 176 177 case IPPROTO_ICMPV6: 178 if (!onlyproto && (nh + offset + 2 < skb->data || 179 pskb_may_pull(skb, nh + offset + 2 - skb->data))) { 180 u8 *icmp; 181 182 nh = skb_network_header(skb); 183 icmp = (u8 *)(nh + offset); 184 fl6->fl6_icmp_type = icmp[0]; 185 fl6->fl6_icmp_code = icmp[1]; 186 } 187 fl6->flowi6_proto = nexthdr; 188 return; 189 190 #if IS_ENABLED(CONFIG_IPV6_MIP6) 191 case IPPROTO_MH: 192 offset += ipv6_optlen(exthdr); 193 if (!onlyproto && (nh + offset + 3 < skb->data || 194 pskb_may_pull(skb, nh + offset + 3 - skb->data))) { 195 struct ip6_mh *mh; 196 197 nh = skb_network_header(skb); 198 mh = (struct ip6_mh *)(nh + offset); 199 fl6->fl6_mh_type = mh->ip6mh_type; 200 } 201 fl6->flowi6_proto = nexthdr; 202 return; 203 #endif 204 205 /* XXX Why are there these headers? */ 206 case IPPROTO_AH: 207 case IPPROTO_ESP: 208 case IPPROTO_COMP: 209 default: 210 fl6->fl6_ipsec_spi = 0; 211 fl6->flowi6_proto = nexthdr; 212 return; 213 } 214 } 215 } 216 217 static inline int xfrm6_garbage_collect(struct dst_ops *ops) 218 { 219 struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); 220 221 xfrm_garbage_collect_deferred(net); 222 return dst_entries_get_fast(ops) > ops->gc_thresh * 2; 223 } 224 225 static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, 226 struct sk_buff *skb, u32 mtu) 227 { 228 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 229 struct dst_entry *path = xdst->route; 230 231 path->ops->update_pmtu(path, sk, skb, mtu); 232 } 233 234 static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk, 235 struct sk_buff *skb) 236 { 237 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 238 struct dst_entry *path = xdst->route; 239 240 path->ops->redirect(path, sk, skb); 241 } 242 243 static void xfrm6_dst_destroy(struct dst_entry *dst) 244 { 245 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 246 247 if (likely(xdst->u.rt6.rt6i_idev)) 248 in6_dev_put(xdst->u.rt6.rt6i_idev); 249 dst_destroy_metrics_generic(dst); 250 xfrm_dst_destroy(xdst); 251 } 252 253 static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 254 int unregister) 255 { 256 struct xfrm_dst *xdst; 257 258 if (!unregister) 259 return; 260 261 xdst = (struct xfrm_dst *)dst; 262 if (xdst->u.rt6.rt6i_idev->dev == dev) { 263 struct inet6_dev *loopback_idev = 264 in6_dev_get(dev_net(dev)->loopback_dev); 265 BUG_ON(!loopback_idev); 266 267 do { 268 in6_dev_put(xdst->u.rt6.rt6i_idev); 269 xdst->u.rt6.rt6i_idev = loopback_idev; 270 in6_dev_hold(loopback_idev); 271 xdst = (struct xfrm_dst *)xdst->u.dst.child; 272 } while (xdst->u.dst.xfrm); 273 274 __in6_dev_put(loopback_idev); 275 } 276 277 xfrm_dst_ifdown(dst, dev); 278 } 279 280 static struct dst_ops xfrm6_dst_ops_template = { 281 .family = AF_INET6, 282 .gc = xfrm6_garbage_collect, 283 .update_pmtu = xfrm6_update_pmtu, 284 .redirect = xfrm6_redirect, 285 .cow_metrics = dst_cow_metrics_generic, 286 .destroy = xfrm6_dst_destroy, 287 .ifdown = xfrm6_dst_ifdown, 288 .local_out = __ip6_local_out, 289 .gc_thresh = INT_MAX, 290 }; 291 292 static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = { 293 .dst_ops = &xfrm6_dst_ops_template, 294 .dst_lookup = xfrm6_dst_lookup, 295 .get_saddr = xfrm6_get_saddr, 296 .decode_session = _decode_session6, 297 .get_tos = xfrm6_get_tos, 298 .init_path = xfrm6_init_path, 299 .fill_dst = xfrm6_fill_dst, 300 .blackhole_route = ip6_blackhole_route, 301 }; 302 303 static int __init xfrm6_policy_init(void) 304 { 305 return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo, AF_INET6); 306 } 307 308 static void xfrm6_policy_fini(void) 309 { 310 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); 311 } 312 313 #ifdef CONFIG_SYSCTL 314 static struct ctl_table xfrm6_policy_table[] = { 315 { 316 .procname = "xfrm6_gc_thresh", 317 .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, 318 .maxlen = sizeof(int), 319 .mode = 0644, 320 .proc_handler = proc_dointvec, 321 }, 322 { } 323 }; 324 325 static int __net_init xfrm6_net_sysctl_init(struct net *net) 326 { 327 struct ctl_table *table; 328 struct ctl_table_header *hdr; 329 330 table = xfrm6_policy_table; 331 if (!net_eq(net, &init_net)) { 332 table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL); 333 if (!table) 334 goto err_alloc; 335 336 table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; 337 } 338 339 hdr = register_net_sysctl(net, "net/ipv6", table); 340 if (!hdr) 341 goto err_reg; 342 343 net->ipv6.sysctl.xfrm6_hdr = hdr; 344 return 0; 345 346 err_reg: 347 if (!net_eq(net, &init_net)) 348 kfree(table); 349 err_alloc: 350 return -ENOMEM; 351 } 352 353 static void __net_exit xfrm6_net_sysctl_exit(struct net *net) 354 { 355 struct ctl_table *table; 356 357 if (!net->ipv6.sysctl.xfrm6_hdr) 358 return; 359 360 table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; 361 unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); 362 if (!net_eq(net, &init_net)) 363 kfree(table); 364 } 365 #else /* CONFIG_SYSCTL */ 366 static inline int xfrm6_net_sysctl_init(struct net *net) 367 { 368 return 0; 369 } 370 371 static inline void xfrm6_net_sysctl_exit(struct net *net) 372 { 373 } 374 #endif 375 376 static int __net_init xfrm6_net_init(struct net *net) 377 { 378 int ret; 379 380 memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template, 381 sizeof(xfrm6_dst_ops_template)); 382 ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops); 383 if (ret) 384 return ret; 385 386 ret = xfrm6_net_sysctl_init(net); 387 if (ret) 388 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 389 390 return ret; 391 } 392 393 static void __net_exit xfrm6_net_exit(struct net *net) 394 { 395 xfrm6_net_sysctl_exit(net); 396 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 397 } 398 399 static struct pernet_operations xfrm6_net_ops = { 400 .init = xfrm6_net_init, 401 .exit = xfrm6_net_exit, 402 }; 403 404 int __init xfrm6_init(void) 405 { 406 int ret; 407 408 ret = xfrm6_policy_init(); 409 if (ret) 410 goto out; 411 ret = xfrm6_state_init(); 412 if (ret) 413 goto out_policy; 414 415 ret = xfrm6_protocol_init(); 416 if (ret) 417 goto out_state; 418 419 register_pernet_subsys(&xfrm6_net_ops); 420 out: 421 return ret; 422 out_state: 423 xfrm6_state_fini(); 424 out_policy: 425 xfrm6_policy_fini(); 426 goto out; 427 } 428 429 void xfrm6_fini(void) 430 { 431 unregister_pernet_subsys(&xfrm6_net_ops); 432 xfrm6_protocol_fini(); 433 xfrm6_policy_fini(); 434 xfrm6_state_fini(); 435 } 436