0001
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
0018 #define SERV4_PORT 4040
0019 #define SERV4_REWRITE_IP 0x7f000001U
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
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
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
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
0144 if (bind_to_device(ctx))
0145 return 0;
0146
0147
0148 if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
0149 return 0;
0150
0151
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";