Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <string.h>
0004 
0005 #include <linux/stddef.h>
0006 #include <linux/bpf.h>
0007 #include <linux/in.h>
0008 #include <linux/in6.h>
0009 #include <sys/socket.h>
0010 #include <netinet/tcp.h>
0011 #include <linux/if.h>
0012 #include <errno.h>
0013 
0014 #include <bpf/bpf_helpers.h>
0015 #include <bpf/bpf_endian.h>
0016 
0017 #define SERV4_IP        0xc0a801feU /* 192.168.1.254 */
0018 #define SERV4_PORT      4040
0019 #define SERV4_REWRITE_IP    0x7f000001U /* 127.0.0.1 */
0020 #define SERV4_REWRITE_PORT  4444
0021 
0022 #ifndef IFNAMSIZ
0023 #define IFNAMSIZ 16
0024 #endif
0025 
0026 static __inline int bind_to_device(struct bpf_sock_addr *ctx)
0027 {
0028     char veth1[IFNAMSIZ] = "test_sock_addr1";
0029     char veth2[IFNAMSIZ] = "test_sock_addr2";
0030     char missing[IFNAMSIZ] = "nonexistent_dev";
0031     char del_bind[IFNAMSIZ] = "";
0032     int veth1_idx, veth2_idx;
0033 
0034     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
0035                &veth1, sizeof(veth1)))
0036         return 1;
0037     if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
0038                &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)
0039         return 1;
0040     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
0041                &veth2, sizeof(veth2)))
0042         return 1;
0043     if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
0044                &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||
0045         veth1_idx == veth2_idx)
0046         return 1;
0047     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
0048                &missing, sizeof(missing)) != -ENODEV)
0049         return 1;
0050     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
0051                &veth1_idx, sizeof(veth1_idx)))
0052         return 1;
0053     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
0054                &del_bind, sizeof(del_bind)))
0055         return 1;
0056 
0057     return 0;
0058 }
0059 
0060 static __inline int bind_reuseport(struct bpf_sock_addr *ctx)
0061 {
0062     int val = 1;
0063 
0064     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
0065                &val, sizeof(val)))
0066         return 1;
0067     if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
0068                &val, sizeof(val)) || !val)
0069         return 1;
0070     val = 0;
0071     if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
0072                &val, sizeof(val)))
0073         return 1;
0074     if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
0075                &val, sizeof(val)) || val)
0076         return 1;
0077 
0078     return 0;
0079 }
0080 
0081 static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)
0082 {
0083     int old, tmp, new = 0xeb9f;
0084 
0085     /* Socket in test case has guarantee that old never equals to new. */
0086     if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||
0087         old == new)
0088         return 1;
0089     if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))
0090         return 1;
0091     if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||
0092         tmp != new)
0093         return 1;
0094     if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))
0095         return 1;
0096 
0097     return 0;
0098 }
0099 
0100 SEC("cgroup/bind4")
0101 int bind_v4_prog(struct bpf_sock_addr *ctx)
0102 {
0103     struct bpf_sock *sk;
0104     __u32 user_ip4;
0105     __u16 user_port;
0106 
0107     sk = ctx->sk;
0108     if (!sk)
0109         return 0;
0110 
0111     if (sk->family != AF_INET)
0112         return 0;
0113 
0114     if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
0115         return 0;
0116 
0117     if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||
0118         ctx->user_port != bpf_htons(SERV4_PORT))
0119         return 0;
0120 
0121     // u8 narrow loads:
0122     user_ip4 = 0;
0123     user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0;
0124     user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8;
0125     user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16;
0126     user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24;
0127     if (ctx->user_ip4 != user_ip4)
0128         return 0;
0129 
0130     user_port = 0;
0131     user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
0132     user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
0133     if (ctx->user_port != user_port)
0134         return 0;
0135 
0136     // u16 narrow loads:
0137     user_ip4 = 0;
0138     user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0;
0139     user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16;
0140     if (ctx->user_ip4 != user_ip4)
0141         return 0;
0142 
0143     /* Bind to device and unbind it. */
0144     if (bind_to_device(ctx))
0145         return 0;
0146 
0147     /* Test for misc socket options. */
0148     if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
0149         return 0;
0150 
0151     /* Set reuseport and unset */
0152     if (bind_reuseport(ctx))
0153         return 0;
0154 
0155     ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);
0156     ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);
0157 
0158     return 1;
0159 }
0160 
0161 char _license[] SEC("license") = "GPL";