hc
2024-02-20 e636c8d336489bf3eed5878299e6cc045bbad077
kernel/net/ipv4/fou.c
....@@ -1,8 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 #include <linux/module.h>
23 #include <linux/errno.h>
34 #include <linux/socket.h>
45 #include <linux/skbuff.h>
56 #include <linux/ip.h>
7
+#include <linux/icmp.h>
68 #include <linux/udp.h>
79 #include <linux/types.h>
810 #include <linux/kernel.h>
....@@ -136,7 +138,7 @@
136138 break;
137139
138140 case 1: {
139
- /* Direct encasulation of IPv4 or IPv6 */
141
+ /* Direct encapsulation of IPv4 or IPv6 */
140142
141143 int prot;
142144
....@@ -170,9 +172,7 @@
170172 /* guehdr may change after pull */
171173 guehdr = (struct guehdr *)&udp_hdr(skb)[1];
172174
173
- hdrlen = sizeof(struct guehdr) + optlen;
174
-
175
- if (guehdr->version != 0 || validate_gue_flags(guehdr, optlen))
175
+ if (validate_gue_flags(guehdr, optlen))
176176 goto drop;
177177
178178 hdrlen = sizeof(struct guehdr) + optlen;
....@@ -237,7 +237,7 @@
237237
238238 /* We can clear the encap_mark for FOU as we are essentially doing
239239 * one of two possible things. We are either adding an L4 tunnel
240
- * header to the outer L3 tunnel header, or we are are simply
240
+ * header to the outer L3 tunnel header, or we are simply
241241 * treating the GRE tunnel header as though it is a UDP protocol
242242 * specific header such as VXLAN or GENEVE.
243243 */
....@@ -429,7 +429,7 @@
429429
430430 /* We can clear the encap_mark for GUE as we are essentially doing
431431 * one of two possible things. We are either adding an L4 tunnel
432
- * header to the outer L3 tunnel header, or we are are simply
432
+ * header to the outer L3 tunnel header, or we are simply
433433 * treating the GRE tunnel header as though it is a UDP protocol
434434 * specific header such as VXLAN or GENEVE.
435435 */
....@@ -500,15 +500,45 @@
500500 return err;
501501 }
502502
503
-static int fou_add_to_port_list(struct net *net, struct fou *fou)
503
+static bool fou_cfg_cmp(struct fou *fou, struct fou_cfg *cfg)
504
+{
505
+ struct sock *sk = fou->sock->sk;
506
+ struct udp_port_cfg *udp_cfg = &cfg->udp_config;
507
+
508
+ if (fou->family != udp_cfg->family ||
509
+ fou->port != udp_cfg->local_udp_port ||
510
+ sk->sk_dport != udp_cfg->peer_udp_port ||
511
+ sk->sk_bound_dev_if != udp_cfg->bind_ifindex)
512
+ return false;
513
+
514
+ if (fou->family == AF_INET) {
515
+ if (sk->sk_rcv_saddr != udp_cfg->local_ip.s_addr ||
516
+ sk->sk_daddr != udp_cfg->peer_ip.s_addr)
517
+ return false;
518
+ else
519
+ return true;
520
+#if IS_ENABLED(CONFIG_IPV6)
521
+ } else {
522
+ if (ipv6_addr_cmp(&sk->sk_v6_rcv_saddr, &udp_cfg->local_ip6) ||
523
+ ipv6_addr_cmp(&sk->sk_v6_daddr, &udp_cfg->peer_ip6))
524
+ return false;
525
+ else
526
+ return true;
527
+#endif
528
+ }
529
+
530
+ return false;
531
+}
532
+
533
+static int fou_add_to_port_list(struct net *net, struct fou *fou,
534
+ struct fou_cfg *cfg)
504535 {
505536 struct fou_net *fn = net_generic(net, fou_net_id);
506537 struct fou *fout;
507538
508539 mutex_lock(&fn->fou_lock);
509540 list_for_each_entry(fout, &fn->fou_list, list) {
510
- if (fou->port == fout->port &&
511
- fou->family == fout->family) {
541
+ if (fou_cfg_cmp(fout, cfg)) {
512542 mutex_unlock(&fn->fou_lock);
513543 return -EALREADY;
514544 }
....@@ -586,7 +616,7 @@
586616
587617 sk->sk_allocation = GFP_ATOMIC;
588618
589
- err = fou_add_to_port_list(net, fou);
619
+ err = fou_add_to_port_list(net, fou, cfg);
590620 if (err)
591621 goto error;
592622
....@@ -606,14 +636,12 @@
606636 static int fou_destroy(struct net *net, struct fou_cfg *cfg)
607637 {
608638 struct fou_net *fn = net_generic(net, fou_net_id);
609
- __be16 port = cfg->udp_config.local_udp_port;
610
- u8 family = cfg->udp_config.family;
611639 int err = -EINVAL;
612640 struct fou *fou;
613641
614642 mutex_lock(&fn->fou_lock);
615643 list_for_each_entry(fou, &fn->fou_list, list) {
616
- if (fou->port == port && fou->family == family) {
644
+ if (fou_cfg_cmp(fou, cfg)) {
617645 fou_release(fou);
618646 err = 0;
619647 break;
....@@ -627,16 +655,27 @@
627655 static struct genl_family fou_nl_family;
628656
629657 static const struct nla_policy fou_nl_policy[FOU_ATTR_MAX + 1] = {
630
- [FOU_ATTR_PORT] = { .type = NLA_U16, },
631
- [FOU_ATTR_AF] = { .type = NLA_U8, },
632
- [FOU_ATTR_IPPROTO] = { .type = NLA_U8, },
633
- [FOU_ATTR_TYPE] = { .type = NLA_U8, },
634
- [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG, },
658
+ [FOU_ATTR_PORT] = { .type = NLA_U16, },
659
+ [FOU_ATTR_AF] = { .type = NLA_U8, },
660
+ [FOU_ATTR_IPPROTO] = { .type = NLA_U8, },
661
+ [FOU_ATTR_TYPE] = { .type = NLA_U8, },
662
+ [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG, },
663
+ [FOU_ATTR_LOCAL_V4] = { .type = NLA_U32, },
664
+ [FOU_ATTR_PEER_V4] = { .type = NLA_U32, },
665
+ [FOU_ATTR_LOCAL_V6] = { .len = sizeof(struct in6_addr), },
666
+ [FOU_ATTR_PEER_V6] = { .len = sizeof(struct in6_addr), },
667
+ [FOU_ATTR_PEER_PORT] = { .type = NLA_U16, },
668
+ [FOU_ATTR_IFINDEX] = { .type = NLA_S32, },
635669 };
636670
637671 static int parse_nl_config(struct genl_info *info,
638672 struct fou_cfg *cfg)
639673 {
674
+ bool has_local = false, has_peer = false;
675
+ struct nlattr *attr;
676
+ int ifindex;
677
+ __be16 port;
678
+
640679 memset(cfg, 0, sizeof(*cfg));
641680
642681 cfg->udp_config.family = AF_INET;
....@@ -658,8 +697,7 @@
658697 }
659698
660699 if (info->attrs[FOU_ATTR_PORT]) {
661
- __be16 port = nla_get_be16(info->attrs[FOU_ATTR_PORT]);
662
-
700
+ port = nla_get_be16(info->attrs[FOU_ATTR_PORT]);
663701 cfg->udp_config.local_udp_port = port;
664702 }
665703
....@@ -671,6 +709,52 @@
671709
672710 if (info->attrs[FOU_ATTR_REMCSUM_NOPARTIAL])
673711 cfg->flags |= FOU_F_REMCSUM_NOPARTIAL;
712
+
713
+ if (cfg->udp_config.family == AF_INET) {
714
+ if (info->attrs[FOU_ATTR_LOCAL_V4]) {
715
+ attr = info->attrs[FOU_ATTR_LOCAL_V4];
716
+ cfg->udp_config.local_ip.s_addr = nla_get_in_addr(attr);
717
+ has_local = true;
718
+ }
719
+
720
+ if (info->attrs[FOU_ATTR_PEER_V4]) {
721
+ attr = info->attrs[FOU_ATTR_PEER_V4];
722
+ cfg->udp_config.peer_ip.s_addr = nla_get_in_addr(attr);
723
+ has_peer = true;
724
+ }
725
+#if IS_ENABLED(CONFIG_IPV6)
726
+ } else {
727
+ if (info->attrs[FOU_ATTR_LOCAL_V6]) {
728
+ attr = info->attrs[FOU_ATTR_LOCAL_V6];
729
+ cfg->udp_config.local_ip6 = nla_get_in6_addr(attr);
730
+ has_local = true;
731
+ }
732
+
733
+ if (info->attrs[FOU_ATTR_PEER_V6]) {
734
+ attr = info->attrs[FOU_ATTR_PEER_V6];
735
+ cfg->udp_config.peer_ip6 = nla_get_in6_addr(attr);
736
+ has_peer = true;
737
+ }
738
+#endif
739
+ }
740
+
741
+ if (has_peer) {
742
+ if (info->attrs[FOU_ATTR_PEER_PORT]) {
743
+ port = nla_get_be16(info->attrs[FOU_ATTR_PEER_PORT]);
744
+ cfg->udp_config.peer_udp_port = port;
745
+ } else {
746
+ return -EINVAL;
747
+ }
748
+ }
749
+
750
+ if (info->attrs[FOU_ATTR_IFINDEX]) {
751
+ if (!has_local)
752
+ return -EINVAL;
753
+
754
+ ifindex = nla_get_s32(info->attrs[FOU_ATTR_IFINDEX]);
755
+
756
+ cfg->udp_config.bind_ifindex = ifindex;
757
+ }
674758
675759 return 0;
676760 }
....@@ -703,15 +787,37 @@
703787
704788 static int fou_fill_info(struct fou *fou, struct sk_buff *msg)
705789 {
790
+ struct sock *sk = fou->sock->sk;
791
+
706792 if (nla_put_u8(msg, FOU_ATTR_AF, fou->sock->sk->sk_family) ||
707793 nla_put_be16(msg, FOU_ATTR_PORT, fou->port) ||
794
+ nla_put_be16(msg, FOU_ATTR_PEER_PORT, sk->sk_dport) ||
708795 nla_put_u8(msg, FOU_ATTR_IPPROTO, fou->protocol) ||
709
- nla_put_u8(msg, FOU_ATTR_TYPE, fou->type))
796
+ nla_put_u8(msg, FOU_ATTR_TYPE, fou->type) ||
797
+ nla_put_s32(msg, FOU_ATTR_IFINDEX, sk->sk_bound_dev_if))
710798 return -1;
711799
712800 if (fou->flags & FOU_F_REMCSUM_NOPARTIAL)
713801 if (nla_put_flag(msg, FOU_ATTR_REMCSUM_NOPARTIAL))
714802 return -1;
803
+
804
+ if (fou->sock->sk->sk_family == AF_INET) {
805
+ if (nla_put_in_addr(msg, FOU_ATTR_LOCAL_V4, sk->sk_rcv_saddr))
806
+ return -1;
807
+
808
+ if (nla_put_in_addr(msg, FOU_ATTR_PEER_V4, sk->sk_daddr))
809
+ return -1;
810
+#if IS_ENABLED(CONFIG_IPV6)
811
+ } else {
812
+ if (nla_put_in6_addr(msg, FOU_ATTR_LOCAL_V6,
813
+ &sk->sk_v6_rcv_saddr))
814
+ return -1;
815
+
816
+ if (nla_put_in6_addr(msg, FOU_ATTR_PEER_V6, &sk->sk_v6_daddr))
817
+ return -1;
818
+#endif
819
+ }
820
+
715821 return 0;
716822 }
717823
....@@ -764,7 +870,7 @@
764870 ret = -ESRCH;
765871 mutex_lock(&fn->fou_lock);
766872 list_for_each_entry(fout, &fn->fou_list, list) {
767
- if (port == fout->port && family == fout->family) {
873
+ if (fou_cfg_cmp(fout, &cfg)) {
768874 ret = fou_dump_info(fout, info->snd_portid,
769875 info->snd_seq, 0, msg,
770876 info->genlhdr->cmd);
....@@ -805,24 +911,24 @@
805911 return skb->len;
806912 }
807913
808
-static const struct genl_ops fou_nl_ops[] = {
914
+static const struct genl_small_ops fou_nl_ops[] = {
809915 {
810916 .cmd = FOU_CMD_ADD,
917
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
811918 .doit = fou_nl_cmd_add_port,
812
- .policy = fou_nl_policy,
813919 .flags = GENL_ADMIN_PERM,
814920 },
815921 {
816922 .cmd = FOU_CMD_DEL,
923
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
817924 .doit = fou_nl_cmd_rm_port,
818
- .policy = fou_nl_policy,
819925 .flags = GENL_ADMIN_PERM,
820926 },
821927 {
822928 .cmd = FOU_CMD_GET,
929
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
823930 .doit = fou_nl_cmd_get_port,
824931 .dumpit = fou_nl_dump,
825
- .policy = fou_nl_policy,
826932 },
827933 };
828934
....@@ -831,10 +937,11 @@
831937 .name = FOU_GENL_NAME,
832938 .version = FOU_GENL_VERSION,
833939 .maxattr = FOU_ATTR_MAX,
940
+ .policy = fou_nl_policy,
834941 .netnsok = true,
835942 .module = THIS_MODULE,
836
- .ops = fou_nl_ops,
837
- .n_ops = ARRAY_SIZE(fou_nl_ops),
943
+ .small_ops = fou_nl_ops,
944
+ .n_small_ops = ARRAY_SIZE(fou_nl_ops),
838945 };
839946
840947 size_t fou_encap_hlen(struct ip_tunnel_encap *e)
....@@ -1005,15 +1112,95 @@
10051112 return 0;
10061113 }
10071114
1115
+static int gue_err_proto_handler(int proto, struct sk_buff *skb, u32 info)
1116
+{
1117
+ const struct net_protocol *ipprot = rcu_dereference(inet_protos[proto]);
1118
+
1119
+ if (ipprot && ipprot->err_handler) {
1120
+ if (!ipprot->err_handler(skb, info))
1121
+ return 0;
1122
+ }
1123
+
1124
+ return -ENOENT;
1125
+}
1126
+
1127
+static int gue_err(struct sk_buff *skb, u32 info)
1128
+{
1129
+ int transport_offset = skb_transport_offset(skb);
1130
+ struct guehdr *guehdr;
1131
+ size_t len, optlen;
1132
+ int ret;
1133
+
1134
+ len = sizeof(struct udphdr) + sizeof(struct guehdr);
1135
+ if (!pskb_may_pull(skb, transport_offset + len))
1136
+ return -EINVAL;
1137
+
1138
+ guehdr = (struct guehdr *)&udp_hdr(skb)[1];
1139
+
1140
+ switch (guehdr->version) {
1141
+ case 0: /* Full GUE header present */
1142
+ break;
1143
+ case 1: {
1144
+ /* Direct encapsulation of IPv4 or IPv6 */
1145
+ skb_set_transport_header(skb, -(int)sizeof(struct icmphdr));
1146
+
1147
+ switch (((struct iphdr *)guehdr)->version) {
1148
+ case 4:
1149
+ ret = gue_err_proto_handler(IPPROTO_IPIP, skb, info);
1150
+ goto out;
1151
+#if IS_ENABLED(CONFIG_IPV6)
1152
+ case 6:
1153
+ ret = gue_err_proto_handler(IPPROTO_IPV6, skb, info);
1154
+ goto out;
1155
+#endif
1156
+ default:
1157
+ ret = -EOPNOTSUPP;
1158
+ goto out;
1159
+ }
1160
+ }
1161
+ default: /* Undefined version */
1162
+ return -EOPNOTSUPP;
1163
+ }
1164
+
1165
+ if (guehdr->control)
1166
+ return -ENOENT;
1167
+
1168
+ optlen = guehdr->hlen << 2;
1169
+
1170
+ if (!pskb_may_pull(skb, transport_offset + len + optlen))
1171
+ return -EINVAL;
1172
+
1173
+ guehdr = (struct guehdr *)&udp_hdr(skb)[1];
1174
+ if (validate_gue_flags(guehdr, optlen))
1175
+ return -EINVAL;
1176
+
1177
+ /* Handling exceptions for direct UDP encapsulation in GUE would lead to
1178
+ * recursion. Besides, this kind of encapsulation can't even be
1179
+ * configured currently. Discard this.
1180
+ */
1181
+ if (guehdr->proto_ctype == IPPROTO_UDP ||
1182
+ guehdr->proto_ctype == IPPROTO_UDPLITE)
1183
+ return -EOPNOTSUPP;
1184
+
1185
+ skb_set_transport_header(skb, -(int)sizeof(struct icmphdr));
1186
+ ret = gue_err_proto_handler(guehdr->proto_ctype, skb, info);
1187
+
1188
+out:
1189
+ skb_set_transport_header(skb, transport_offset);
1190
+ return ret;
1191
+}
1192
+
10081193
10091194 static const struct ip_tunnel_encap_ops fou_iptun_ops = {
10101195 .encap_hlen = fou_encap_hlen,
10111196 .build_header = fou_build_header,
1197
+ .err_handler = gue_err,
10121198 };
10131199
10141200 static const struct ip_tunnel_encap_ops gue_iptun_ops = {
10151201 .encap_hlen = gue_encap_hlen,
10161202 .build_header = gue_build_header,
1203
+ .err_handler = gue_err,
10171204 };
10181205
10191206 static int ip_tunnel_encap_add_fou_ops(void)
....@@ -1117,3 +1304,4 @@
11171304 module_exit(fou_fini);
11181305 MODULE_AUTHOR("Tom Herbert <therbert@google.com>");
11191306 MODULE_LICENSE("GPL");
1307
+MODULE_DESCRIPTION("Foo over UDP");