168 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <string.h>4 5#include <linux/stddef.h>6#include <linux/bpf.h>7#include <linux/in.h>8#include <linux/in6.h>9#include <linux/if.h>10#include <errno.h>11 12#include <bpf/bpf_helpers.h>13#include <bpf/bpf_endian.h>14 15#include "bind_prog.h"16 17#define SERV4_IP 0xc0a801feU /* 192.168.1.254 */18#define SERV4_PORT 404019#define SERV4_REWRITE_IP 0x7f000001U /* 127.0.0.1 */20#define SERV4_REWRITE_PORT 444421 22#ifndef IFNAMSIZ23#define IFNAMSIZ 1624#endif25 26static __inline int bind_to_device(struct bpf_sock_addr *ctx)27{28 char veth1[IFNAMSIZ] = "test_sock_addr1";29 char veth2[IFNAMSIZ] = "test_sock_addr2";30 char missing[IFNAMSIZ] = "nonexistent_dev";31 char del_bind[IFNAMSIZ] = "";32 int veth1_idx, veth2_idx;33 34 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,35 &veth1, sizeof(veth1)))36 return 1;37 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,38 &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)39 return 1;40 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,41 &veth2, sizeof(veth2)))42 return 1;43 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,44 &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||45 veth1_idx == veth2_idx)46 return 1;47 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,48 &missing, sizeof(missing)) != -ENODEV)49 return 1;50 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,51 &veth1_idx, sizeof(veth1_idx)))52 return 1;53 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,54 &del_bind, sizeof(del_bind)))55 return 1;56 57 return 0;58}59 60static __inline int bind_reuseport(struct bpf_sock_addr *ctx)61{62 int val = 1;63 64 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,65 &val, sizeof(val)))66 return 1;67 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,68 &val, sizeof(val)) || !val)69 return 1;70 val = 0;71 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,72 &val, sizeof(val)))73 return 1;74 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,75 &val, sizeof(val)) || val)76 return 1;77 78 return 0;79}80 81static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)82{83 int old, tmp, new = 0xeb9f;84 85 /* Socket in test case has guarantee that old never equals to new. */86 if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||87 old == new)88 return 1;89 if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))90 return 1;91 if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||92 tmp != new)93 return 1;94 if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))95 return 1;96 97 return 0;98}99 100SEC("cgroup/bind4")101int bind_v4_prog(struct bpf_sock_addr *ctx)102{103 struct bpf_sock *sk;104 __u32 user_ip4;105 __u16 user_port;106 107 sk = ctx->sk;108 if (!sk)109 return 0;110 111 if (sk->family != AF_INET)112 return 0;113 114 if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)115 return 0;116 117 if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||118 ctx->user_port != bpf_htons(SERV4_PORT))119 return 0;120 121 // u8 narrow loads:122 user_ip4 = 0;123 user_ip4 |= load_byte(ctx->user_ip4, 0, sizeof(user_ip4));124 user_ip4 |= load_byte(ctx->user_ip4, 1, sizeof(user_ip4));125 user_ip4 |= load_byte(ctx->user_ip4, 2, sizeof(user_ip4));126 user_ip4 |= load_byte(ctx->user_ip4, 3, sizeof(user_ip4));127 if (ctx->user_ip4 != user_ip4)128 return 0;129 130 user_port = 0;131 user_port |= load_byte(ctx->user_port, 0, sizeof(user_port));132 user_port |= load_byte(ctx->user_port, 1, sizeof(user_port));133 if (ctx->user_port != user_port)134 return 0;135 136 // u16 narrow loads:137 user_ip4 = 0;138 user_ip4 |= load_word(ctx->user_ip4, 0, sizeof(user_ip4));139 user_ip4 |= load_word(ctx->user_ip4, 1, sizeof(user_ip4));140 if (ctx->user_ip4 != user_ip4)141 return 0;142 143 /* Bind to device and unbind it. */144 if (bind_to_device(ctx))145 return 0;146 147 /* Test for misc socket options. */148 if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))149 return 0;150 151 /* Set reuseport and unset */152 if (bind_reuseport(ctx))153 return 0;154 155 ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);156 ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);157 158 return 1;159}160 161SEC("cgroup/bind4")162int bind_v4_deny_prog(struct bpf_sock_addr *ctx)163{164 return 0;165}166 167char _license[] SEC("license") = "GPL";168