1a999696cSStanislav Fomichev // SPDX-License-Identifier: GPL-2.0 2a999696cSStanislav Fomichev 3a999696cSStanislav Fomichev #include <string.h> 4a999696cSStanislav Fomichev 5a999696cSStanislav Fomichev #include <linux/stddef.h> 6a999696cSStanislav Fomichev #include <linux/bpf.h> 7a999696cSStanislav Fomichev #include <linux/in.h> 8a999696cSStanislav Fomichev #include <linux/in6.h> 9a999696cSStanislav Fomichev #include <sys/socket.h> 10a999696cSStanislav Fomichev #include <netinet/tcp.h> 11a999696cSStanislav Fomichev #include <linux/if.h> 12a999696cSStanislav Fomichev #include <errno.h> 13a999696cSStanislav Fomichev 14a999696cSStanislav Fomichev #include <bpf/bpf_helpers.h> 15a999696cSStanislav Fomichev #include <bpf/bpf_endian.h> 16a999696cSStanislav Fomichev 17a999696cSStanislav Fomichev #define SERV4_IP 0xc0a801feU /* 192.168.1.254 */ 18a999696cSStanislav Fomichev #define SERV4_PORT 4040 19a999696cSStanislav Fomichev #define SERV4_REWRITE_IP 0x7f000001U /* 127.0.0.1 */ 20a999696cSStanislav Fomichev #define SERV4_REWRITE_PORT 4444 21a999696cSStanislav Fomichev 22a540c81aSStanislav Fomichev #ifndef IFNAMSIZ 23a540c81aSStanislav Fomichev #define IFNAMSIZ 16 24a540c81aSStanislav Fomichev #endif 25a540c81aSStanislav Fomichev 26a540c81aSStanislav Fomichev static __inline int bind_to_device(struct bpf_sock_addr *ctx) 27a540c81aSStanislav Fomichev { 28a540c81aSStanislav Fomichev char veth1[IFNAMSIZ] = "test_sock_addr1"; 29a540c81aSStanislav Fomichev char veth2[IFNAMSIZ] = "test_sock_addr2"; 30a540c81aSStanislav Fomichev char missing[IFNAMSIZ] = "nonexistent_dev"; 31a540c81aSStanislav Fomichev char del_bind[IFNAMSIZ] = ""; 32*3218231dSDaniel Borkmann int veth1_idx, veth2_idx; 33a540c81aSStanislav Fomichev 34a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 35a540c81aSStanislav Fomichev &veth1, sizeof(veth1))) 36a540c81aSStanislav Fomichev return 1; 37*3218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 38*3218231dSDaniel Borkmann &veth1_idx, sizeof(veth1_idx)) || !veth1_idx) 39*3218231dSDaniel Borkmann return 1; 40a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 41a540c81aSStanislav Fomichev &veth2, sizeof(veth2))) 42a540c81aSStanislav Fomichev return 1; 43*3218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 44*3218231dSDaniel Borkmann &veth2_idx, sizeof(veth2_idx)) || !veth2_idx || 45*3218231dSDaniel Borkmann veth1_idx == veth2_idx) 46*3218231dSDaniel Borkmann return 1; 47a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 48a540c81aSStanislav Fomichev &missing, sizeof(missing)) != -ENODEV) 49a540c81aSStanislav Fomichev return 1; 50*3218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 51*3218231dSDaniel Borkmann &veth1_idx, sizeof(veth1_idx))) 52*3218231dSDaniel Borkmann return 1; 53a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 54a540c81aSStanislav Fomichev &del_bind, sizeof(del_bind))) 55a540c81aSStanislav Fomichev return 1; 56a540c81aSStanislav Fomichev 57a540c81aSStanislav Fomichev return 0; 58a540c81aSStanislav Fomichev } 59a540c81aSStanislav Fomichev 60*3218231dSDaniel Borkmann static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt) 61*3218231dSDaniel Borkmann { 62*3218231dSDaniel Borkmann int old, tmp, new = 0xeb9f; 63*3218231dSDaniel Borkmann 64*3218231dSDaniel Borkmann /* Socket in test case has guarantee that old never equals to new. */ 65*3218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) || 66*3218231dSDaniel Borkmann old == new) 67*3218231dSDaniel Borkmann return 1; 68*3218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new))) 69*3218231dSDaniel Borkmann return 1; 70*3218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) || 71*3218231dSDaniel Borkmann tmp != new) 72*3218231dSDaniel Borkmann return 1; 73*3218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old))) 74*3218231dSDaniel Borkmann return 1; 75*3218231dSDaniel Borkmann 76*3218231dSDaniel Borkmann return 0; 77*3218231dSDaniel Borkmann } 78*3218231dSDaniel Borkmann 79a999696cSStanislav Fomichev SEC("cgroup/bind4") 80a999696cSStanislav Fomichev int bind_v4_prog(struct bpf_sock_addr *ctx) 81a999696cSStanislav Fomichev { 82a999696cSStanislav Fomichev struct bpf_sock *sk; 83a999696cSStanislav Fomichev __u32 user_ip4; 84a999696cSStanislav Fomichev __u16 user_port; 85a999696cSStanislav Fomichev 86a999696cSStanislav Fomichev sk = ctx->sk; 87a999696cSStanislav Fomichev if (!sk) 88a999696cSStanislav Fomichev return 0; 89a999696cSStanislav Fomichev 90a999696cSStanislav Fomichev if (sk->family != AF_INET) 91a999696cSStanislav Fomichev return 0; 92a999696cSStanislav Fomichev 93a999696cSStanislav Fomichev if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) 94a999696cSStanislav Fomichev return 0; 95a999696cSStanislav Fomichev 96a999696cSStanislav Fomichev if (ctx->user_ip4 != bpf_htonl(SERV4_IP) || 97a999696cSStanislav Fomichev ctx->user_port != bpf_htons(SERV4_PORT)) 98a999696cSStanislav Fomichev return 0; 99a999696cSStanislav Fomichev 100a999696cSStanislav Fomichev // u8 narrow loads: 101a999696cSStanislav Fomichev user_ip4 = 0; 102a999696cSStanislav Fomichev user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0; 103a999696cSStanislav Fomichev user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8; 104a999696cSStanislav Fomichev user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16; 105a999696cSStanislav Fomichev user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24; 106a999696cSStanislav Fomichev if (ctx->user_ip4 != user_ip4) 107a999696cSStanislav Fomichev return 0; 108a999696cSStanislav Fomichev 109a999696cSStanislav Fomichev user_port = 0; 110a999696cSStanislav Fomichev user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0; 111a999696cSStanislav Fomichev user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8; 112a999696cSStanislav Fomichev if (ctx->user_port != user_port) 113a999696cSStanislav Fomichev return 0; 114a999696cSStanislav Fomichev 115a999696cSStanislav Fomichev // u16 narrow loads: 116a999696cSStanislav Fomichev user_ip4 = 0; 117a999696cSStanislav Fomichev user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0; 118a999696cSStanislav Fomichev user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16; 119a999696cSStanislav Fomichev if (ctx->user_ip4 != user_ip4) 120a999696cSStanislav Fomichev return 0; 121a999696cSStanislav Fomichev 122a540c81aSStanislav Fomichev /* Bind to device and unbind it. */ 123a540c81aSStanislav Fomichev if (bind_to_device(ctx)) 124a540c81aSStanislav Fomichev return 0; 125a540c81aSStanislav Fomichev 126*3218231dSDaniel Borkmann /* Test for misc socket options. */ 127*3218231dSDaniel Borkmann if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY)) 128*3218231dSDaniel Borkmann return 0; 129*3218231dSDaniel Borkmann 130a999696cSStanislav Fomichev ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP); 131a999696cSStanislav Fomichev ctx->user_port = bpf_htons(SERV4_REWRITE_PORT); 132a999696cSStanislav Fomichev 133a999696cSStanislav Fomichev return 1; 134a999696cSStanislav Fomichev } 135a999696cSStanislav Fomichev 136a999696cSStanislav Fomichev char _license[] SEC("license") = "GPL"; 137