seg6.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * SR-IPv6 implementation
  4. *
  5. * Author:
  6. * David Lebrun <david.lebrun@uclouvain.be>
  7. */
  8. #include <linux/errno.h>
  9. #include <linux/types.h>
  10. #include <linux/socket.h>
  11. #include <linux/net.h>
  12. #include <linux/in6.h>
  13. #include <linux/slab.h>
  14. #include <linux/rhashtable.h>
  15. #include <net/ipv6.h>
  16. #include <net/protocol.h>
  17. #include <net/seg6.h>
  18. #include <net/genetlink.h>
  19. #include <linux/seg6.h>
  20. #include <linux/seg6_genl.h>
  21. #include <net/seg6_hmac.h>
  22. bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
  23. {
  24. unsigned int tlv_offset;
  25. int max_last_entry;
  26. int trailing;
  27. if (srh->type != IPV6_SRCRT_TYPE_4)
  28. return false;
  29. if (((srh->hdrlen + 1) << 3) != len)
  30. return false;
  31. if (!reduced && srh->segments_left > srh->first_segment) {
  32. return false;
  33. } else {
  34. max_last_entry = (srh->hdrlen / 2) - 1;
  35. if (srh->first_segment > max_last_entry)
  36. return false;
  37. if (srh->segments_left > srh->first_segment + 1)
  38. return false;
  39. }
  40. tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
  41. trailing = len - tlv_offset;
  42. if (trailing < 0)
  43. return false;
  44. while (trailing) {
  45. struct sr6_tlv *tlv;
  46. unsigned int tlv_len;
  47. if (trailing < sizeof(*tlv))
  48. return false;
  49. tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
  50. tlv_len = sizeof(*tlv) + tlv->len;
  51. trailing -= tlv_len;
  52. if (trailing < 0)
  53. return false;
  54. tlv_offset += tlv_len;
  55. }
  56. return true;
  57. }
  58. struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags)
  59. {
  60. struct ipv6_sr_hdr *srh;
  61. int len, srhoff = 0;
  62. if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
  63. return NULL;
  64. if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
  65. return NULL;
  66. srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
  67. len = (srh->hdrlen + 1) << 3;
  68. if (!pskb_may_pull(skb, srhoff + len))
  69. return NULL;
  70. /* note that pskb_may_pull may change pointers in header;
  71. * for this reason it is necessary to reload them when needed.
  72. */
  73. srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
  74. if (!seg6_validate_srh(srh, len, true))
  75. return NULL;
  76. return srh;
  77. }
  78. /* Determine if an ICMP invoking packet contains a segment routing
  79. * header. If it does, extract the offset to the true destination
  80. * address, which is in the first segment address.
  81. */
  82. void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt)
  83. {
  84. __u16 network_header = skb->network_header;
  85. struct ipv6_sr_hdr *srh;
  86. /* Update network header to point to the invoking packet
  87. * inside the ICMP packet, so we can use the seg6_get_srh()
  88. * helper.
  89. */
  90. skb_reset_network_header(skb);
  91. srh = seg6_get_srh(skb, 0);
  92. if (!srh)
  93. goto out;
  94. if (srh->type != IPV6_SRCRT_TYPE_4)
  95. goto out;
  96. opt->flags |= IP6SKB_SEG6;
  97. opt->srhoff = (unsigned char *)srh - skb->data;
  98. out:
  99. /* Restore the network header back to the ICMP packet */
  100. skb->network_header = network_header;
  101. }
  102. static struct genl_family seg6_genl_family;
  103. static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
  104. [SEG6_ATTR_DST] = { .type = NLA_BINARY,
  105. .len = sizeof(struct in6_addr) },
  106. [SEG6_ATTR_DSTLEN] = { .type = NLA_S32, },
  107. [SEG6_ATTR_HMACKEYID] = { .type = NLA_U32, },
  108. [SEG6_ATTR_SECRET] = { .type = NLA_BINARY, },
  109. [SEG6_ATTR_SECRETLEN] = { .type = NLA_U8, },
  110. [SEG6_ATTR_ALGID] = { .type = NLA_U8, },
  111. [SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
  112. };
  113. #ifdef CONFIG_IPV6_SEG6_HMAC
  114. static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
  115. {
  116. struct net *net = genl_info_net(info);
  117. struct seg6_pernet_data *sdata;
  118. struct seg6_hmac_info *hinfo;
  119. u32 hmackeyid;
  120. char *secret;
  121. int err = 0;
  122. u8 algid;
  123. u8 slen;
  124. sdata = seg6_pernet(net);
  125. if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
  126. !info->attrs[SEG6_ATTR_SECRETLEN] ||
  127. !info->attrs[SEG6_ATTR_ALGID])
  128. return -EINVAL;
  129. hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
  130. slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
  131. algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
  132. if (hmackeyid == 0)
  133. return -EINVAL;
  134. if (slen > SEG6_HMAC_SECRET_LEN)
  135. return -EINVAL;
  136. mutex_lock(&sdata->lock);
  137. hinfo = seg6_hmac_info_lookup(net, hmackeyid);
  138. if (!slen) {
  139. err = seg6_hmac_info_del(net, hmackeyid);
  140. goto out_unlock;
  141. }
  142. if (!info->attrs[SEG6_ATTR_SECRET]) {
  143. err = -EINVAL;
  144. goto out_unlock;
  145. }
  146. if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) {
  147. err = -EINVAL;
  148. goto out_unlock;
  149. }
  150. if (hinfo) {
  151. err = seg6_hmac_info_del(net, hmackeyid);
  152. if (err)
  153. goto out_unlock;
  154. }
  155. secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
  156. hinfo = kzalloc_obj(*hinfo);
  157. if (!hinfo) {
  158. err = -ENOMEM;
  159. goto out_unlock;
  160. }
  161. memcpy(hinfo->secret, secret, slen);
  162. hinfo->slen = slen;
  163. hinfo->alg_id = algid;
  164. hinfo->hmackeyid = hmackeyid;
  165. err = seg6_hmac_info_add(net, hmackeyid, hinfo);
  166. if (err)
  167. kfree(hinfo);
  168. out_unlock:
  169. mutex_unlock(&sdata->lock);
  170. return err;
  171. }
  172. #else
  173. static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
  174. {
  175. return -ENOTSUPP;
  176. }
  177. #endif
  178. static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
  179. {
  180. struct net *net = genl_info_net(info);
  181. struct in6_addr *val, *t_old, *t_new;
  182. struct seg6_pernet_data *sdata;
  183. sdata = seg6_pernet(net);
  184. if (!info->attrs[SEG6_ATTR_DST])
  185. return -EINVAL;
  186. val = nla_data(info->attrs[SEG6_ATTR_DST]);
  187. t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
  188. if (!t_new)
  189. return -ENOMEM;
  190. mutex_lock(&sdata->lock);
  191. t_old = sdata->tun_src;
  192. rcu_assign_pointer(sdata->tun_src, t_new);
  193. mutex_unlock(&sdata->lock);
  194. synchronize_net();
  195. kfree(t_old);
  196. return 0;
  197. }
  198. static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
  199. {
  200. struct net *net = genl_info_net(info);
  201. struct in6_addr *tun_src;
  202. struct sk_buff *msg;
  203. void *hdr;
  204. msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  205. if (!msg)
  206. return -ENOMEM;
  207. hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
  208. &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
  209. if (!hdr)
  210. goto free_msg;
  211. rcu_read_lock();
  212. tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
  213. if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
  214. goto nla_put_failure;
  215. rcu_read_unlock();
  216. genlmsg_end(msg, hdr);
  217. return genlmsg_reply(msg, info);
  218. nla_put_failure:
  219. rcu_read_unlock();
  220. free_msg:
  221. nlmsg_free(msg);
  222. return -ENOMEM;
  223. }
  224. #ifdef CONFIG_IPV6_SEG6_HMAC
  225. static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
  226. struct sk_buff *msg)
  227. {
  228. if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
  229. nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
  230. nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
  231. nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
  232. return -1;
  233. return 0;
  234. }
  235. static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
  236. u32 portid, u32 seq, u32 flags,
  237. struct sk_buff *skb, u8 cmd)
  238. {
  239. void *hdr;
  240. hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
  241. if (!hdr)
  242. return -ENOMEM;
  243. if (__seg6_hmac_fill_info(hinfo, skb) < 0)
  244. goto nla_put_failure;
  245. genlmsg_end(skb, hdr);
  246. return 0;
  247. nla_put_failure:
  248. genlmsg_cancel(skb, hdr);
  249. return -EMSGSIZE;
  250. }
  251. static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
  252. {
  253. struct net *net = sock_net(cb->skb->sk);
  254. struct seg6_pernet_data *sdata;
  255. struct rhashtable_iter *iter;
  256. sdata = seg6_pernet(net);
  257. iter = (struct rhashtable_iter *)cb->args[0];
  258. if (!iter) {
  259. iter = kmalloc_obj(*iter);
  260. if (!iter)
  261. return -ENOMEM;
  262. cb->args[0] = (long)iter;
  263. }
  264. rhashtable_walk_enter(&sdata->hmac_infos, iter);
  265. return 0;
  266. }
  267. static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
  268. {
  269. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  270. rhashtable_walk_exit(iter);
  271. kfree(iter);
  272. return 0;
  273. }
  274. static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
  275. {
  276. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  277. struct seg6_hmac_info *hinfo;
  278. int ret;
  279. rhashtable_walk_start(iter);
  280. for (;;) {
  281. hinfo = rhashtable_walk_next(iter);
  282. if (IS_ERR(hinfo)) {
  283. if (PTR_ERR(hinfo) == -EAGAIN)
  284. continue;
  285. ret = PTR_ERR(hinfo);
  286. goto done;
  287. } else if (!hinfo) {
  288. break;
  289. }
  290. ret = __seg6_genl_dumphmac_element(hinfo,
  291. NETLINK_CB(cb->skb).portid,
  292. cb->nlh->nlmsg_seq,
  293. NLM_F_MULTI,
  294. skb, SEG6_CMD_DUMPHMAC);
  295. if (ret)
  296. goto done;
  297. }
  298. ret = skb->len;
  299. done:
  300. rhashtable_walk_stop(iter);
  301. return ret;
  302. }
  303. #else
  304. static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
  305. {
  306. return 0;
  307. }
  308. static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
  309. {
  310. return 0;
  311. }
  312. static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
  313. {
  314. return -ENOTSUPP;
  315. }
  316. #endif
  317. static int __net_init seg6_net_init(struct net *net)
  318. {
  319. struct seg6_pernet_data *sdata;
  320. sdata = kzalloc_obj(*sdata);
  321. if (!sdata)
  322. return -ENOMEM;
  323. mutex_init(&sdata->lock);
  324. sdata->tun_src = kzalloc_obj(*sdata->tun_src);
  325. if (!sdata->tun_src) {
  326. kfree(sdata);
  327. return -ENOMEM;
  328. }
  329. net->ipv6.seg6_data = sdata;
  330. if (seg6_hmac_net_init(net)) {
  331. kfree(rcu_dereference_raw(sdata->tun_src));
  332. kfree(sdata);
  333. return -ENOMEM;
  334. }
  335. return 0;
  336. }
  337. static void __net_exit seg6_net_exit(struct net *net)
  338. {
  339. struct seg6_pernet_data *sdata = seg6_pernet(net);
  340. seg6_hmac_net_exit(net);
  341. kfree(rcu_dereference_raw(sdata->tun_src));
  342. kfree(sdata);
  343. }
  344. static struct pernet_operations ip6_segments_ops = {
  345. .init = seg6_net_init,
  346. .exit = seg6_net_exit,
  347. };
  348. static const struct genl_ops seg6_genl_ops[] = {
  349. {
  350. .cmd = SEG6_CMD_SETHMAC,
  351. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  352. .doit = seg6_genl_sethmac,
  353. .flags = GENL_ADMIN_PERM,
  354. },
  355. {
  356. .cmd = SEG6_CMD_DUMPHMAC,
  357. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  358. .start = seg6_genl_dumphmac_start,
  359. .dumpit = seg6_genl_dumphmac,
  360. .done = seg6_genl_dumphmac_done,
  361. .flags = GENL_ADMIN_PERM,
  362. },
  363. {
  364. .cmd = SEG6_CMD_SET_TUNSRC,
  365. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  366. .doit = seg6_genl_set_tunsrc,
  367. .flags = GENL_ADMIN_PERM,
  368. },
  369. {
  370. .cmd = SEG6_CMD_GET_TUNSRC,
  371. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  372. .doit = seg6_genl_get_tunsrc,
  373. .flags = GENL_ADMIN_PERM,
  374. },
  375. };
  376. static struct genl_family seg6_genl_family __ro_after_init = {
  377. .hdrsize = 0,
  378. .name = SEG6_GENL_NAME,
  379. .version = SEG6_GENL_VERSION,
  380. .maxattr = SEG6_ATTR_MAX,
  381. .policy = seg6_genl_policy,
  382. .netnsok = true,
  383. .parallel_ops = true,
  384. .ops = seg6_genl_ops,
  385. .n_ops = ARRAY_SIZE(seg6_genl_ops),
  386. .resv_start_op = SEG6_CMD_GET_TUNSRC + 1,
  387. .module = THIS_MODULE,
  388. };
  389. int __init seg6_init(void)
  390. {
  391. int err;
  392. err = register_pernet_subsys(&ip6_segments_ops);
  393. if (err)
  394. goto out;
  395. err = genl_register_family(&seg6_genl_family);
  396. if (err)
  397. goto out_unregister_pernet;
  398. err = seg6_iptunnel_init();
  399. if (err)
  400. goto out_unregister_genl;
  401. err = seg6_local_init();
  402. if (err)
  403. goto out_unregister_iptun;
  404. pr_info("Segment Routing with IPv6\n");
  405. out:
  406. return err;
  407. out_unregister_iptun:
  408. seg6_iptunnel_exit();
  409. out_unregister_genl:
  410. genl_unregister_family(&seg6_genl_family);
  411. out_unregister_pernet:
  412. unregister_pernet_subsys(&ip6_segments_ops);
  413. goto out;
  414. }
  415. void seg6_exit(void)
  416. {
  417. seg6_local_exit();
  418. seg6_iptunnel_exit();
  419. genl_unregister_family(&seg6_genl_family);
  420. unregister_pernet_subsys(&ip6_segments_ops);
  421. }