forked from kmesh-net/kmesh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support srcip and dstports rbac in xdp
Signed-off-by: superCharge-xsy <[email protected]>
- Loading branch information
1 parent
46c5c72
commit 4c6d4e8
Showing
4 changed files
with
373 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,346 @@ | ||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ | ||
/* Copyright Authors of Kmesh */ | ||
|
||
#ifndef __AUTHZ_H__ | ||
#define __AUTHZ_H__ | ||
|
||
#include "workload_common.h" | ||
#include "bpf_log.h" | ||
#include "workloadapi/security/authorization.pb-c.h" | ||
|
||
#define AUTH_ALLOW 0 | ||
#define AUTH_DENY 1 | ||
#define UNMATCHED 0 | ||
#define MATCHED 1 | ||
#define UNSUPPORTED 2 | ||
#define MAX_MEMBER_NUM_PER_POLICY 16 | ||
#define TYPE_SRCIP (1) | ||
#define TYPE_DSTIP (1 << 1) | ||
#define TYPE_DSTPORT (1 << 2) | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(key_size, BPF_DATA_MAX_LEN); | ||
__uint(value_size, sizeof(Istio__Security__Authorization)); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
__uint(max_entries, MAP_SIZE_OF_AUTH); | ||
} map_of_authz SEC(".maps"); | ||
|
||
struct xdp_info { | ||
struct ethhdr *ethh; | ||
union { | ||
struct iphdr *iph; | ||
struct ipv6hdr *ip6h; | ||
}; | ||
struct tcphdr *tcph; | ||
}; | ||
|
||
static inline Istio__Security__Authorization *map_lookup_authz(const char *key) | ||
{ | ||
return (Istio__Security__Authorization*)kmesh_map_lookup_elem(&map_of_authz, key); | ||
} | ||
|
||
|
||
static inline __u32 convert_ipv4_to_u32(const struct ProtobufCBinaryData *ipv4_data) | ||
{ | ||
if (ipv4_data->len != 4) { | ||
return 0; | ||
} | ||
|
||
return (ipv4_data->data[0] << 24) | | ||
(ipv4_data->data[1] << 16) | | ||
(ipv4_data->data[2] << 8) | | ||
(ipv4_data->data[3] << 0); | ||
} | ||
|
||
static inline int matchIpv4(__u32 ruleIp, __u32 preFixLen, __be32 targetIP) | ||
{ | ||
__u32 mask = 0; | ||
|
||
if (preFixLen > 32) { | ||
return UNMATCHED; | ||
} | ||
mask = 0xFFFFFFFF << (32 - preFixLen); | ||
if ((ruleIp & mask) == (targetIP & mask)) { | ||
return MATCHED; | ||
} | ||
return 0; | ||
|
||
} | ||
|
||
static inline int matchIp(struct ProtobufCBinaryData *addrInfo, __u32 preFixLen, struct bpf_sock_tuple *tuple_info, __u8 type) { | ||
if (preFixLen > 32) { | ||
return UNMATCHED; | ||
} | ||
if (addrInfo->len == 4) { | ||
if (type & TYPE_SRCIP) { | ||
return matchIpv4(convert_ipv4_to_u32(addrInfo), preFixLen, tuple_info->ipv4.saddr); | ||
} | ||
} else { | ||
return UNSUPPORTED; | ||
} | ||
return UNMATCHED; | ||
|
||
} | ||
|
||
static inline int matchSrcIPs(Istio__Security__Match *match, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
void *srcPtrs = NULL; | ||
void *notSrcPtrs = NULL; | ||
__u32 inSrcList = 0; | ||
__u32 i; | ||
|
||
if (match->n_source_ips == 0 && match->n_not_source_ips == 0) { | ||
return MATCHED; | ||
} | ||
|
||
// match not_srcIPs | ||
if (match->n_not_source_ips != 0) { | ||
notSrcPtrs = kmesh_get_ptr_val(match->not_source_ips); | ||
if (!notSrcPtrs) { | ||
BPF_LOG(ERR, AUTH, "failed to get not_srcips ptr\n"); | ||
return UNMATCHED; | ||
} | ||
|
||
#pragma unroll | ||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= match-> n_not_source_ips) { | ||
break; | ||
} | ||
Istio__Security__Address *srcAddr = (Istio__Security__Address *)kmesh_get_ptr_val((void *)*((__u64 *)notSrcPtrs + i)); | ||
if (!srcAddr) { | ||
continue; | ||
} | ||
// todo: ProtobufCBinaryData address是否需要使用mesh_get_ptr_val | ||
// in n_src_ips means in blacklist, return unmatch | ||
if (matchIp(&srcAddr->address, srcAddr->length, tuple_info, TYPE_SRCIP) == MATCHED) { | ||
return UNMATCHED; | ||
} | ||
} | ||
} | ||
|
||
if (match->n_source_ips != 0) { | ||
srcPtrs = kmesh_get_ptr_val(match->source_ips); | ||
if (!srcPtrs) { | ||
BPF_LOG(ERR, AUTH, "failed to get srcips ptr\n"); | ||
return UNMATCHED; | ||
} | ||
|
||
#pragma unroll | ||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= match->n_source_ips) { | ||
break; | ||
} | ||
Istio__Security__Address *srcAddr = (Istio__Security__Address *)kmesh_get_ptr_val((void *)*((__u64 *)srcPtrs + i)); | ||
if (!srcAddr) { | ||
continue; | ||
} | ||
// todo: ProtobufCBinaryData address是否需要使用mesh_get_ptr_val | ||
if (matchIp(&srcAddr->address, srcAddr->length, tuple_info, TYPE_SRCIP) == MATCHED) { | ||
return MATCHED; | ||
} | ||
} | ||
} | ||
return UNMATCHED; | ||
} | ||
|
||
static inline int matchDstPorts(Istio__Security__Match *match, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
__u32 *notPorts = NULL; | ||
__u32 i; | ||
|
||
if (match->n_destination_ports == 0 && match->n_not_destination_ports == 0) { | ||
return MATCHED; | ||
} | ||
|
||
if (match->n_not_destination_ports != 0) { | ||
//match->not_destination_ports | ||
notPorts = kmesh_get_ptr_val(match->not_destination_ports); | ||
if (!notPorts) { | ||
BPF_LOG(ERR, AUTH, "failed to get not_destination_ports ptr\n"); | ||
return UNMATCHED; | ||
} | ||
|
||
for (i = 0; i <MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= match->n_not_destination_ports) { | ||
break; | ||
} | ||
|
||
if (notPorts[i] == tuple_info->ipv4.dport || notPorts[i] == tuple_info->ipv6.dport) { | ||
BPF_LOG(INFO, AUTH, "match not_ports[i]: %d\n", notPorts[i]); | ||
return UNMATCHED; | ||
} | ||
} | ||
|
||
} | ||
|
||
if (match->n_destination_ports != 0) { | ||
__u32 *ports = kmesh_get_ptr_val(match->destination_ports); | ||
if (!ports) { | ||
BPF_LOG(ERR, AUTH, "failed to get destination_ports ptr\n"); | ||
return UNMATCHED; | ||
} | ||
|
||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= match->n_destination_ports) { | ||
break; | ||
} | ||
|
||
if (ports[i] == tuple_info->ipv4.dport || ports[i] == tuple_info->ipv6.dport) { | ||
return MATCHED; | ||
} | ||
} | ||
} | ||
return UNMATCHED; | ||
} | ||
|
||
static inline int match_check(Istio__Security__Match *match, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
__u32 matchResult; | ||
|
||
// todo: if some type not supported, need retun UNSUPPORT and allow this packet | ||
// if multiple types are set, they are AND-ed, all matched is a match | ||
matchResult = matchSrcIPs(match, tuple_info); | ||
if (matchResult != MATCHED) { | ||
return matchResult; | ||
} | ||
|
||
matchResult = matchDstPorts(match, tuple_info); | ||
return matchResult; | ||
} | ||
|
||
static inline int clause_match_check(Istio__Security__Clause *cl, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
void *matchsPtr = NULL; | ||
__u32 i; | ||
|
||
if (cl->n_matches == 0) { | ||
BPF_LOG(ERR, AUTH, "auth clause has no match info\n"); | ||
return UNMATCHED; | ||
} | ||
matchsPtr = kmesh_get_ptr_val(cl->matches); | ||
if (!matchsPtr) { | ||
BPF_LOG(ERR, AUTH, "failed to get matches from clause\n"); | ||
return MATCHED; | ||
} | ||
|
||
#pragma unroll | ||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= cl->n_matches) { | ||
break; | ||
} | ||
Istio__Security__Match *match = (Istio__Security__Match *)kmesh_get_ptr_val((void *)*((__u64 *)matchsPtr + i)); | ||
if (!match) { | ||
continue; | ||
} | ||
// if any match matches, it is a match | ||
if(match_check(match, tuple_info) == MATCHED) { | ||
return MATCHED; | ||
} | ||
} | ||
return UNMATCHED; | ||
} | ||
|
||
static inline int rule_match_check(Istio__Security__Rule *rule, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
void *clausesPtr = NULL; | ||
__u32 i; | ||
|
||
if (rule->n_clauses == 0) { | ||
BPF_LOG(ERR, AUTH, "rule has no clauses\n"); | ||
return UNMATCHED; | ||
} | ||
// Clauses are AND-ed. | ||
clausesPtr = kmesh_get_ptr_val(rule->clauses); | ||
if (!clausesPtr) { | ||
BPF_LOG(ERR, AUTH, "failed to get clauses from rule\n"); | ||
return UNMATCHED; | ||
} | ||
|
||
#pragma unroll | ||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= rule->n_clauses) { | ||
break; | ||
} | ||
Istio__Security__Clause *clause = (Istio__Security__Clause *)kmesh_get_ptr_val((void *)*((__u64 *)clausesPtr + i)); | ||
if (!clause) { | ||
continue; | ||
} | ||
|
||
if (clause_match_check(clause, tuple_info) == UNMATCHED) { | ||
return UNMATCHED; | ||
} | ||
} | ||
return MATCHED; | ||
} | ||
|
||
static inline int policy_manage(Istio__Security__Authorization* policy, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
void *rulesPtr = NULL; | ||
Istio__Security__Rule * rule = NULL; | ||
int matchFlag = 0; | ||
__u32 i; | ||
|
||
if (policy->n_rules == 0) { | ||
BPF_LOG(ERR, AUTH, "auth policy %s has no rules\n", kmesh_get_ptr_val(policy->name)); | ||
return AUTH_DENY; | ||
} | ||
|
||
// Rules are OR-ed. | ||
rulesPtr = kmesh_get_ptr_val(policy->rules); | ||
if (!rulesPtr) { | ||
BPF_LOG(ERR, AUTH, "failed to get rules from policy %s\n", kmesh_get_ptr_val(policy->name)); | ||
return AUTH_DENY; | ||
} | ||
|
||
#pragma unroll | ||
for (i = 0; i < MAX_MEMBER_NUM_PER_POLICY; i++) { | ||
if (i >= policy->n_rules) { | ||
break; | ||
} | ||
rule = (Istio__Security__Rule *)kmesh_get_ptr_val((void *)*((__u64 *)rulesPtr + i)); | ||
if (!rule) { | ||
continue; | ||
} | ||
if (rule_match_check(rule, tuple_info) == MATCHED) { | ||
matchFlag = 1; | ||
break; | ||
} | ||
} | ||
|
||
if (policy->action == ISTIO__SECURITY__ACTION__ALLOW) { | ||
return matchFlag ? AUTH_ALLOW : AUTH_DENY; | ||
} else if (policy->action == ISTIO__SECURITY__ACTION__DENY) { | ||
return matchFlag ? AUTH_DENY : AUTH_ALLOW; | ||
} | ||
return AUTH_ALLOW; | ||
} | ||
|
||
static inline int match_workload_scope(struct bpf_sock_tuple *tuple_info) | ||
{ | ||
// todo:for workloadPolicys, do lookup policyInfo from authMap & check match | ||
int ret = 0; | ||
char policy_key[BPF_DATA_MAX_LEN] = "test-policy"; // 键为 "test-policy" | ||
Istio__Security__Authorization *policy = map_lookup_authz(policy_key); | ||
ret = policy_manage(policy, tuple_info); | ||
if (ret == AUTH_DENY) { | ||
BPF_LOG(ERR, AUTH, "policy %s manage result deny\n", kmesh_get_ptr_val(policy->name)); | ||
} | ||
return ret; | ||
|
||
} | ||
|
||
static inline int xdp_deny_packet(struct xdp_info *info) | ||
{ | ||
return XDP_DROP; | ||
} | ||
|
||
static inline int rbac_manage(struct xdp_info *info, struct bpf_sock_tuple *tuple_info) | ||
{ | ||
int workloadMatchAction = match_workload_scope(tuple_info); | ||
if (workloadMatchAction == AUTH_ALLOW) | ||
return XDP_PASS; | ||
return xdp_deny_packet(info); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.