SEC("sk_lookup") int lookup_pass(struct bpf_sk_lookup *ctx)
{ return SK_PASS;
}
SEC("sk_lookup") int lookup_drop(struct bpf_sk_lookup *ctx)
{ return SK_DROP;
}
SEC("sk_lookup") int check_ifindex(struct bpf_sk_lookup *ctx)
{ if (ctx->ingress_ifindex == 1) return SK_DROP; return SK_PASS;
}
SEC("sk_reuseport") int reuseport_pass(struct sk_reuseport_md *ctx)
{ return SK_PASS;
}
SEC("sk_reuseport") int reuseport_drop(struct sk_reuseport_md *ctx)
{ return SK_DROP;
}
/* Redirect packets destined for port DST_PORT to socket at redir_map[0]. */
SEC("sk_lookup") int redir_port(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk; int err;
if (ctx->local_port != DST_PORT) return SK_PASS;
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk) return SK_PASS;
/* Redirect packets destined for DST_IP4 address to socket at redir_map[0]. */
SEC("sk_lookup") int redir_ip4(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk; int err;
if (ctx->family != AF_INET) return SK_PASS; if (ctx->local_port != DST_PORT) return SK_PASS; if (ctx->local_ip4 != DST_IP4) return SK_PASS;
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk) return SK_PASS;
/* Redirect packets destined for DST_IP6 address to socket at redir_map[0]. */
SEC("sk_lookup") int redir_ip6(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk; int err;
if (ctx->family != AF_INET6) return SK_PASS; if (ctx->local_port != DST_PORT) return SK_PASS; if (ctx->local_ip6[0] != DST_IP6[0] ||
ctx->local_ip6[1] != DST_IP6[1] ||
ctx->local_ip6[2] != DST_IP6[2] ||
ctx->local_ip6[3] != DST_IP6[3]) return SK_PASS;
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk) return SK_PASS;
/* Check that bpf_sk_assign() returns -EEXIST if socket already selected. */
SEC("sk_lookup") int sk_assign_eexist(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk; int err, ret;
ret = SK_DROP;
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B); if (!sk) goto out;
err = bpf_sk_assign(ctx, sk, 0); if (err) goto out;
bpf_sk_release(sk);
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk) goto out;
err = bpf_sk_assign(ctx, sk, 0); if (err != -EEXIST) {
bpf_printk("sk_assign returned %d, expected %d\n",
err, -EEXIST); goto out;
}
ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
out: if (sk)
bpf_sk_release(sk); return ret;
}
/* Check that bpf_sk_assign(BPF_SK_LOOKUP_F_REPLACE) can override selection. */
SEC("sk_lookup") int sk_assign_replace_flag(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk; int err, ret;
ret = SK_DROP;
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk) goto out;
err = bpf_sk_assign(ctx, sk, 0); if (err) goto out;
bpf_sk_release(sk);
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B); if (!sk) goto out;
err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE); if (err) {
bpf_printk("sk_assign returned %d, expected 0\n", err); goto out;
}
ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
out: if (sk)
bpf_sk_release(sk); return ret;
}
/* Check that bpf_sk_assign(sk=NULL) is accepted. */
SEC("sk_lookup") int sk_assign_null(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk = NULL; int err, ret;
ret = SK_DROP;
err = bpf_sk_assign(ctx, NULL, 0); if (err) {
bpf_printk("sk_assign returned %d, expected 0\n", err); goto out;
}
sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B); if (!sk) goto out;
err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE); if (err) {
bpf_printk("sk_assign returned %d, expected 0\n", err); goto out;
}
if (ctx->sk != sk) goto out;
err = bpf_sk_assign(ctx, NULL, 0); if (err != -EEXIST) goto out;
err = bpf_sk_assign(ctx, NULL, BPF_SK_LOOKUP_F_REPLACE); if (err) goto out;
err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE); if (err) goto out;
ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
out: if (sk)
bpf_sk_release(sk); return ret;
}
/* Check that selected sk is accessible through context. */
SEC("sk_lookup") int access_ctx_sk(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk1 = NULL, *sk2 = NULL; int err, ret;
ret = SK_DROP;
/* Try accessing unassigned (NULL) ctx->sk field */ if (ctx->sk && ctx->sk->family != AF_INET) goto out;
/* Assign a value to ctx->sk */
sk1 = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A); if (!sk1) goto out;
err = bpf_sk_assign(ctx, sk1, 0); if (err) goto out; if (ctx->sk != sk1) goto out;
ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
out: if (sk1)
bpf_sk_release(sk1); if (sk2)
bpf_sk_release(sk2); return ret;
}
/* Check narrow loads from ctx fields that support them. * * Narrow loads of size >= target field size from a non-zero offset * are not covered because they give bogus results, that is the * verifier ignores the offset.
*/
SEC("sk_lookup") int ctx_narrow_access(struct bpf_sk_lookup *ctx)
{ struct bpf_sock *sk;
__u32 val_u32; bool v4;
v4 = (ctx->family == AF_INET);
/* Narrow loads from family field */ if (LSB(ctx->family, 0) != (v4 ? AF_INET : AF_INET6) ||
LSB(ctx->family, 1) != 0 || LSB(ctx->family, 2) != 0 || LSB(ctx->family, 3) != 0) return SK_DROP; if (LSW(ctx->family, 0) != (v4 ? AF_INET : AF_INET6)) return SK_DROP;
/* Narrow loads from protocol field */ if (LSB(ctx->protocol, 0) != IPPROTO_TCP ||
LSB(ctx->protocol, 1) != 0 || LSB(ctx->protocol, 2) != 0 || LSB(ctx->protocol, 3) != 0) return SK_DROP; if (LSW(ctx->protocol, 0) != IPPROTO_TCP) return SK_DROP;
/* * NOTE: 4-byte load from bpf_sk_lookup at remote_port offset * is quirky. It gets rewritten by the access converter to a * 2-byte load for backward compatibility. Treating the load * result as a be16 value makes the code portable across * little- and big-endian platforms.
*/
val_u32 = *(__u32 *)&ctx->remote_port; if (val_u32 != SRC_PORT) return SK_DROP;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.