diff --git a/component/control/bpf_utils.go b/component/control/bpf_utils.go index 5070304..bcba85d 100644 --- a/component/control/bpf_utils.go +++ b/component/control/bpf_utils.go @@ -27,8 +27,8 @@ type _bpfPortRange struct { func (r _bpfPortRange) Encode() uint32 { var b [4]byte - binary.LittleEndian.PutUint16(b[:2], r.PortStart) - binary.LittleEndian.PutUint16(b[2:], r.PortEnd) + binary.BigEndian.PutUint16(b[:2], r.PortStart) + binary.BigEndian.PutUint16(b[2:], r.PortEnd) return binary.BigEndian.Uint32(b[:]) } diff --git a/component/control/control_plane.go b/component/control/control_plane.go index 8ec9c66..d4230f8 100644 --- a/component/control/control_plane.go +++ b/component/control/control_plane.go @@ -93,10 +93,10 @@ retryLoadBpf: } mapName, _, _ := strings.Cut(after, ":") _ = os.Remove(filepath.Join(pinPath, mapName)) - log.Warnf("New map format was incompatible with existing map %v, and the old one was removed.", mapName) + log.Infof("Incompatible new map format with existing map %v detected; removed the old one.", mapName) goto retryLoadBpf } - // Get detailed log from ebpf.internal.*VerifierError + // Get detailed log from ebpf.internal.(*VerifierError) if log.IsLevelEnabled(logrus.TraceLevel) { if v := reflect.Indirect(reflect.ValueOf(errors.Unwrap(errors.Unwrap(err)))); v.Kind() == reflect.Struct { if log := v.FieldByName("Log"); log.IsValid() { @@ -199,12 +199,12 @@ retryLoadBpf: ); err != nil { return nil, fmt.Errorf("ApplyRulesOptimizers error: \n %w", err) } - if log.IsLevelEnabled(logrus.TraceLevel) { + if log.IsLevelEnabled(logrus.DebugLevel) { var debugBuilder strings.Builder for _, rule := range rules { debugBuilder.WriteString(rule.String(true) + "\n") } - log.Tracef("RoutingA:\n%vfinal: %v\n", debugBuilder.String(), routingA.Final) + log.Debugf("RoutingA:\n%vfinal: %v\n", debugBuilder.String(), routingA.Final) } if err = routing.ApplyMatcherBuilder(builder, rules, routingA.Final); err != nil { return nil, fmt.Errorf("ApplyMatcherBuilder: %w", err) diff --git a/component/control/kern/tproxy.c b/component/control/kern/tproxy.c index eb1fa4b..c5e67dd 100644 --- a/component/control/kern/tproxy.c +++ b/component/control/kern/tproxy.c @@ -104,7 +104,7 @@ struct { // LPM key: struct { - __uint(type, BPF_MAP_TYPE_HASH); + __uint(type, BPF_MAP_TYPE_PERCPU_HASH); __type(key, __u32); __type(value, struct lpm_key); __uint(max_entries, 3); @@ -113,17 +113,17 @@ struct { // h_sport, h_dport: struct { - __uint(type, BPF_MAP_TYPE_HASH); + __uint(type, BPF_MAP_TYPE_PERCPU_HASH); __type(key, __u32); - __type(value, __u32); + __type(value, __u16); __uint(max_entries, 2); __uint(pinning, LIBBPF_PIN_BY_NAME); } h_port_map SEC(".maps"); // l4proto, ipversion: struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, __u64); + __uint(type, BPF_MAP_TYPE_PERCPU_HASH); + __type(key, __u32); __type(value, __u32); __uint(max_entries, 2); __uint(pinning, LIBBPF_PIN_BY_NAME); @@ -277,9 +277,9 @@ static __always_inline __u32 l4_checksum_off(__u8 proto, __u8 ihl) { return ETH_HLEN + ihl * 4 + l4_checksum_rel_off(proto); } -static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6, - __u8 proto, __u8 ihl, __be32 old_ip[4], - __be32 new_ip[4], bool is_dest) { +static __always_inline int rewrite_ip(struct __sk_buff *skb, bool is_ipv6, + __u8 proto, __u8 ihl, __be32 old_ip[4], + __be32 new_ip[4], bool is_dest) { // Nothing to do. if (equal_ipv6_format(old_ip, new_ip)) { return 0; @@ -287,7 +287,7 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6, // bpf_printk("%pI6->%pI6", old_ip, new_ip); __u32 l4_cksm_off = l4_checksum_off(proto, ihl); - long ret; + int ret; // BPF_F_PSEUDO_HDR indicates the part we want to modify is part of the // pseudo header. __u32 l4flags = BPF_F_PSEUDO_HDR; @@ -309,7 +309,7 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6, sizeof(_new_ip)))) { return ret; } - bpf_printk("%pI4 -> %pI4", &_old_ip, &_new_ip); + // bpf_printk("%pI4 -> %pI4", &_old_ip, &_new_ip); ret = bpf_skb_store_bytes(skb, is_dest ? IPV4_DST_OFF : IPV4_SRC_OFF, &_new_ip, sizeof(_new_ip), 0); @@ -324,7 +324,7 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6, bpf_printk("bpf_l4_csum_replace: %ld", ret); return ret; } - bpf_printk("%pI6 -> %pI6", old_ip, new_ip); + // bpf_printk("%pI6 -> %pI6", old_ip, new_ip); ret = bpf_skb_store_bytes(skb, is_dest ? IPV6_DST_OFF : IPV6_SRC_OFF, new_ip, IPV6_BYTE_LENGTH, 0); @@ -337,9 +337,9 @@ static __always_inline long rewrite_ip(struct __sk_buff *skb, bool is_ipv6, return 0; } -static __always_inline long rewrite_port(struct __sk_buff *skb, __u8 proto, - __u8 ihl, __be16 old_port, - __be16 new_port, bool is_dest) { +static __always_inline int rewrite_port(struct __sk_buff *skb, __u8 proto, + __u8 ihl, __be16 old_port, + __be16 new_port, bool is_dest) { // Nothing to do. if (old_port == new_port) { return 0; @@ -370,7 +370,7 @@ static __always_inline long rewrite_port(struct __sk_buff *skb, __u8 proto, // bpf_printk("%u -> %u", bpf_ntohs(old_port), bpf_ntohs(new_port)); - long ret; + int ret; if ((ret = bpf_l4_csum_replace(skb, cksm_off, old_port, new_port, l4flags | sizeof(new_port)))) { bpf_printk("bpf_l4_csum_replace: %ld", ret); @@ -385,7 +385,7 @@ static __always_inline long rewrite_port(struct __sk_buff *skb, __u8 proto, return 0; } -static __always_inline long +static __always_inline int handle_ipv6_extensions(void *data, void *data_end, __u32 hdr, struct tcphdr **tcph, struct udphdr **udph, __u8 *ihl) { __u8 hdr_length = 0; @@ -454,7 +454,7 @@ handle_ipv6_extensions(void *data, void *data_end, __u32 hdr, return 1; } -static __always_inline long +static __always_inline int parse_transport(struct __sk_buff *skb, struct ethhdr **ethh, struct iphdr **iph, struct ipv6hdr **ipv6h, struct tcphdr **tcph, struct udphdr **udph, __u8 *ihl) { @@ -517,8 +517,8 @@ parse_transport(struct __sk_buff *skb, struct ethhdr **ethh, struct iphdr **iph, return 1; } -static __always_inline long ip_is_host(bool is_ipv6, __u32 ifindex, - __be32 ip[4], __be32 tproxy_ip[4]) { +static __always_inline int ip_is_host(bool is_ipv6, __u32 ifindex, __be32 ip[4], + __be32 tproxy_ip[4]) { if (tproxy_ip) { struct if_ip *if_ip = bpf_map_lookup_elem(&ifindex_tproxy_ip_map, &ifindex); if (unlikely(!if_ip)) { @@ -540,8 +540,8 @@ static __always_inline long ip_is_host(bool is_ipv6, __u32 ifindex, return bpf_map_lookup_elem(&host_ip_lpm, &lpm_key) ? 1 : 0; } -static __always_inline long adjust_udp_len(struct __sk_buff *skb, __u16 oldlen, - __u32 ihl, __u16 len_diff) { +static __always_inline int adjust_udp_len(struct __sk_buff *skb, __u16 oldlen, + __u32 ihl, __u16 len_diff) { if (unlikely(!len_diff)) { return 0; } @@ -561,7 +561,7 @@ static __always_inline long adjust_udp_len(struct __sk_buff *skb, __u16 oldlen, __be16 newlen = bpf_htons(bpf_ntohs(oldlen) + len_diff); // Calculate checksum and store the new value. - long ret; + int ret; __u32 udp_csum_off = l4_checksum_off(IPPROTO_UDP, ihl); // replace twice because len exists both pseudo hdr and hdr. @@ -586,8 +586,8 @@ static __always_inline long adjust_udp_len(struct __sk_buff *skb, __u16 oldlen, return 0; } -static __always_inline long adjust_ipv4_len(struct __sk_buff *skb, __u16 oldlen, - __u16 len_diff) { +static __always_inline int adjust_ipv4_len(struct __sk_buff *skb, __u16 oldlen, + __u16 len_diff) { if (unlikely(!len_diff)) { return 0; } @@ -607,7 +607,7 @@ static __always_inline long adjust_ipv4_len(struct __sk_buff *skb, __u16 oldlen, __be16 newlen = bpf_htons(bpf_ntohs(oldlen) + len_diff); // Calculate checksum and store the new value. - long ret; + int ret; if ((ret = bpf_l3_csum_replace(skb, IPV4_CSUM_OFF, oldlen, newlen, sizeof(oldlen)))) { bpf_printk("bpf_l3_csum_replace newudplen: %ld", ret); @@ -622,10 +622,10 @@ static __always_inline long adjust_ipv4_len(struct __sk_buff *skb, __u16 oldlen, return 0; } -static __always_inline long encap_after_udp_hdr(struct __sk_buff *skb, - bool is_ipv6, __u8 ihl, - __be16 iphdr_tot_len, - void *newhdr, __u32 newhdrlen) { +static __always_inline int encap_after_udp_hdr(struct __sk_buff *skb, + bool is_ipv6, __u8 ihl, + __be16 iphdr_tot_len, + void *newhdr, __u32 newhdrlen) { if (unlikely(newhdrlen % 4 != 0)) { bpf_printk("encap_after_udp_hdr: unexpected newhdrlen value %u :must " "be a multiple of 4", @@ -633,7 +633,7 @@ static __always_inline long encap_after_udp_hdr(struct __sk_buff *skb, return -EINVAL; } - long ret = 0; + int ret = 0; long ip_off = ETH_HLEN; // Calculate offsets using add instead of subtract to avoid verifier problems. long ipp_len = ihl * 4; @@ -699,7 +699,7 @@ static __always_inline int decap_after_udp_hdr(struct __sk_buff *skb, decap_hdrlen); return -EINVAL; } - long ret = 0; + int ret = 0; long ip_off = ETH_HLEN; // Calculate offsets using add instead of subtract to avoid verifier problems. long ipp_len = ihl * 4; @@ -767,17 +767,23 @@ static __always_inline int decap_after_udp_hdr(struct __sk_buff *skb, } // Do not use __always_inline here because this function is too heavy. -static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], - __be32 daddr[4], __be32 mac[4]) { +static int routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], + __be32 daddr[4], __be32 mac[4]) { #define _l4proto flag[0] #define _ipversion flag[1] #define _hash flag[2] - /// TODO: BPF_MAP_UPDATE_BATCH - // To avoid racing. - __u64 key = ((__u64)_hash << 32) + ROUTING_TYPE_L4PROTO; - bpf_map_update_elem(&l4proto_ipversion_map, &key, &_l4proto, BPF_ANY); + /// TODO: BPF_MAP_UPDATE_BATCH ? + __u32 key = ROUTING_TYPE_L4PROTO; + int ret; + if ((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key, &_l4proto, + BPF_ANY))) { + return ret; + }; key = ROUTING_TYPE_IPVERSION; - bpf_map_update_elem(&l4proto_ipversion_map, &key, &_ipversion, BPF_ANY); + if ((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key, &_ipversion, + BPF_ANY))) { + return ret; + }; // Define variables for further use. __u16 h_dport; @@ -790,9 +796,13 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], h_sport = bpf_ntohs(((struct udphdr *)l4_hdr)->source); } key = ROUTING_TYPE_SOURCE_PORT; - bpf_map_update_elem(&h_port_map, &key, &h_sport, BPF_ANY); + if ((ret = bpf_map_update_elem(&h_port_map, &key, &h_sport, BPF_ANY))) { + return ret; + }; key = ROUTING_TYPE_PORT; - bpf_map_update_elem(&h_port_map, &key, &h_dport, BPF_ANY); + if ((ret = bpf_map_update_elem(&h_port_map, &key, &h_dport, BPF_ANY))) { + return ret; + }; // Modify DNS upstream for routing. if (h_dport == 53 && _l4proto == L4PROTO_TYPE_UDP) { @@ -812,12 +822,20 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], __builtin_memcpy(lpm_key_daddr.data, daddr, IPV6_BYTE_LENGTH); __builtin_memcpy(lpm_key_mac.data, mac, IPV6_BYTE_LENGTH); // bpf_printk("mac: %pI6", mac); - key = (key & (__u32)0) | (__u32)ROUTING_TYPE_IP_SET; - bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_daddr, BPF_ANY); - key = (key & (__u32)0) | (__u32)ROUTING_TYPE_SOURCE_IP_SET; - bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_saddr, BPF_ANY); - key = (key & (__u32)0) | (__u32)ROUTING_TYPE_MAC; - bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_mac, BPF_ANY); + key = ROUTING_TYPE_IP_SET; + if ((ret = + bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_daddr, BPF_ANY))) { + return ret; + }; + key = ROUTING_TYPE_SOURCE_IP_SET; + if ((ret = + bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_saddr, BPF_ANY))) { + return ret; + }; + key = ROUTING_TYPE_MAC; + if ((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_mac, BPF_ANY))) { + return ret; + }; struct map_lpm_type *lpm; struct match_set *match_set; @@ -828,6 +846,7 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], bool good_subrule = false; struct domain_routing *domain_routing; __u32 *p_u32; + __u16 *p_u16; #pragma unroll for (__u32 i = 0; i < MAX_ROUTING_LEN; i++) { @@ -837,10 +856,19 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], return -EFAULT; } if (bad_rule || good_subrule) { + key = match_set->type; + // bpf_printk("key(match_set->type): %llu", key); + // bpf_printk("Skip to judge. bad_rule: %d, good_subrule: %d", bad_rule, + // good_subrule); goto before_next_loop; } - key = (key & (__u32)0) | (__u32)match_set->type; + key = match_set->type; + // bpf_printk("key(match_set->type): %llu", key); if ((lpm_key = bpf_map_lookup_elem(&lpm_key_map, &key))) { + // bpf_printk( + // "CHECK: lpm_key_map, match_set->type: %u, not: %d, outbound: %u", + // match_set->type, match_set->not, match_set->outbound); + // bpf_printk("\tip: %pI6", lpm_key->data); lpm = bpf_map_lookup_elem(&lpm_array_map, &match_set->index); if (unlikely(!lpm)) { return -EFAULT; @@ -849,16 +877,29 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], // match_set hits. good_subrule = true; } - } else if ((p_u32 = bpf_map_lookup_elem(&h_port_map, &key))) { - if (*p_u32 >= match_set->port_range.port_start && - *p_u32 <= match_set->port_range.port_end) { + } else if ((p_u16 = bpf_map_lookup_elem(&h_port_map, &key))) { + // bpf_printk( + // "CHECK: h_port_map, match_set->type: %u, not: %d, outbound: %u", + // match_set->type, match_set->not, match_set->outbound); + // bpf_printk("\tport: %u, range: [%u, %u]", *p_u16, + // match_set->port_range.port_start, + // match_set->port_range.port_end); + if (*p_u16 >= match_set->port_range.port_start && + *p_u16 <= match_set->port_range.port_end) { good_subrule = true; } } else if ((p_u32 = bpf_map_lookup_elem(&l4proto_ipversion_map, &key))) { + // bpf_printk("CHECK: l4proto_ipversion_map, match_set->type: %u, not: %d, + // " + // "outbound: %u", + // match_set->type, match_set->not, match_set->outbound); if (*p_u32 & match_set->__value) { good_subrule = true; } } else if (match_set->type == ROUTING_TYPE_DOMAIN_SET) { + // bpf_printk("CHECK: domain, match_set->type: %u, not: %d, " + // "outbound: %u", + // match_set->type, match_set->not, match_set->outbound); // Bottleneck of insns limit. // We fixed it by invoking bpf_map_lookup_elem here. @@ -874,37 +915,42 @@ static long routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4], good_subrule = true; } } else if (match_set->type == ROUTING_TYPE_FINAL) { + // bpf_printk("CHECK: hit final"); good_subrule = true; } else { + // bpf_printk("CHECK: , match_set->type: %u, not: %d, " + // "outbound: %u", + // match_set->type, match_set->not, match_set->outbound); return -EINVAL; } before_next_loop: - if (match_set->outbound != OUTBOUND_LOGICAL_OR && !bad_rule) { + if (match_set->outbound != OUTBOUND_LOGICAL_OR) { // This match_set reaches the end of subrule. // We are now at end of rule, or next match_set belongs to another // subrule. + if (good_subrule == match_set->not ) { // This subrule does not hit. bad_rule = true; - } else { - // This subrule hits. - // Reset the good_subrule flag. - good_subrule = false; } + + // Reset good_subrule. + good_subrule = false; } + if ((match_set->outbound & OUTBOUND_LOGICAL_MASK) != OUTBOUND_LOGICAL_MASK) { // Tail of a rule (line). // Decide whether to hit. if (!bad_rule) { + // bpf_printk("MATCHED: match_set->type: %u, match_set->not: %d", + // match_set->type, match_set->not ); if (match_set->outbound == OUTBOUND_DIRECT && h_dport == 53 && _l4proto == L4PROTO_TYPE_UDP) { // DNS packet should go through control plane. return OUTBOUND_CONTROL_PLANE_DIRECT; } - // bpf_printk("match_set->type: %d, match_set->not: %d", match_set->type, - // match_set->not ); return match_set->outbound; } bad_rule = false; @@ -928,7 +974,7 @@ int tproxy_ingress(struct __sk_buff *skb) { __sum16 bak_cksm; __u8 ihl; bool tcp_state_syn; - long ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl); + int ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl); if (ret) { bpf_printk("parse_transport: %ld", ret); return TC_ACT_OK; @@ -965,7 +1011,7 @@ int tproxy_ingress(struct __sk_buff *skb) { // If this packet is sent to this host, accept it. __u32 tproxy_ip[4]; - long to_host = ip_is_host(ipv6h, skb->ifindex, daddr, tproxy_ip); + int to_host = ip_is_host(ipv6h, skb->ifindex, daddr, tproxy_ip); if (to_host < 0) { // error // bpf_printk("to_host: %ld", to_host); return TC_ACT_OK; @@ -1018,6 +1064,9 @@ int tproxy_ingress(struct __sk_buff *skb) { } outbound = ret; + + // Print only new connection. + bpf_printk("tcp: outbound: %u, %pI6", outbound, daddr); } else { // bpf_printk("[%X]Old Connection", bpf_ntohl(tcph->seq)); // The TCP connection exists. @@ -1029,7 +1078,6 @@ int tproxy_ingress(struct __sk_buff *skb) { outbound = dst->outbound; } - bpf_printk("tcp: outbound: %u, %pI6", outbound, daddr); if (outbound == OUTBOUND_DIRECT) { return TC_ACT_OK; } else if (unlikely(outbound == OUTBOUND_BLOCK)) { @@ -1165,7 +1213,7 @@ int tproxy_egress(struct __sk_buff *skb) { __sum16 bak_cksm; __u8 l4_proto; __u8 ihl; - long ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl); + int ret = parse_transport(skb, ðh, &iph, &ipv6h, &tcph, &udph, &ihl); if (ret) { return TC_ACT_OK; } diff --git a/component/control/routing_matcher_builder.go b/component/control/routing_matcher_builder.go index 49d5e44..d622d0c 100644 --- a/component/control/routing_matcher_builder.go +++ b/component/control/routing_matcher_builder.go @@ -116,8 +116,12 @@ func (b *RoutingMatcherBuilder) AddIp(f *config_parser.Function, values []netip. }) } -func (b *RoutingMatcherBuilder) AddPort(f *config_parser.Function, values [][2]uint16, outbound string) { - for _, value := range values { +func (b *RoutingMatcherBuilder) AddPort(f *config_parser.Function, values [][2]uint16, _outbound string) { + for i, value := range values { + outbound := routing.FakeOutbound_OR + if i == len(values)-1 { + outbound = _outbound + } b.rules = append(b.rules, bpfMatchSet{ Type: uint32(consts.RoutingType_Port), Value: _bpfPortRange{ @@ -144,8 +148,12 @@ func (b *RoutingMatcherBuilder) AddSourceIp(f *config_parser.Function, values [] }) } -func (b *RoutingMatcherBuilder) AddSourcePort(f *config_parser.Function, values [][2]uint16, outbound string) { - for _, value := range values { +func (b *RoutingMatcherBuilder) AddSourcePort(f *config_parser.Function, values [][2]uint16, _outbound string) { + for i, value := range values { + outbound := routing.FakeOutbound_OR + if i == len(values)-1 { + outbound = _outbound + } b.rules = append(b.rules, bpfMatchSet{ Type: uint32(consts.RoutingType_SourcePort), Value: _bpfPortRange{ @@ -232,6 +240,3 @@ func (b *RoutingMatcherBuilder) Build() (err error) { return nil } -//func (b *RoutingMatcherBuilder) AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string) { -// logrus.Debugln(f.Not, f.Name, key, outbound) -//} diff --git a/component/outbound/dialer/alive_dialer_set.go b/component/outbound/dialer/alive_dialer_set.go index 6b2c4ac..77b4e1e 100644 --- a/component/outbound/dialer/alive_dialer_set.go +++ b/component/outbound/dialer/alive_dialer_set.go @@ -145,7 +145,11 @@ func (a *AliveDialerSet) SetAlive(dialer *Dialer, alive bool) { a.calcMinLatency() } if a.minLatency.dialer != oldBestDialer { - a.log.Infof("Group [%v] switched dialer to <%v> (%v): %v", a.dialerGroupName, a.minLatency.dialer.Name(), a.selectionPolicy, a.minLatency.latency) + newDialerName := "" + if a.minLatency.dialer != nil { + newDialerName = a.minLatency.dialer.Name() + } + a.log.Infof("Group [%v] switched dialer to <%v> (%v): %v", a.dialerGroupName, newDialerName, a.selectionPolicy, a.minLatency.latency) } } else { if alive && minPolicy && a.minLatency.dialer == nil { diff --git a/component/routing/matcher_builder.go b/component/routing/matcher_builder.go index e372b0c..277123c 100644 --- a/component/routing/matcher_builder.go +++ b/component/routing/matcher_builder.go @@ -7,6 +7,7 @@ package routing import ( "fmt" + "github.com/sirupsen/logrus" "github.com/v2rayA/dae/common" "github.com/v2rayA/dae/common/consts" "github.com/v2rayA/dae/pkg/config_parser" @@ -60,6 +61,8 @@ func ParsePrefixes(values []string) (cidrs []netip.Prefix, err error) { func ApplyMatcherBuilder(builder MatcherBuilder, rules []*config_parser.RoutingRule, finalOutbound string) (err error) { for _, rule := range rules { + logrus.Debugln("[rule]", rule.String(true)) + // rule is like: domain(domain:baidu.com) && port(443) -> proxy for iFunc, f := range rule.AndFunctions { // f is like: domain(domain:baidu.com) @@ -75,6 +78,15 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []*config_parser.RoutingR } } + { + // Debug + symNot := "" + if f.Not { + symNot = "!" + } + logrus.Debugf("\t%v%v(%v) -> %v", symNot, f.Name, key, outbound) + } + builder.AddAnyBefore(f, key, paramValueGroup, outbound) switch f.Name { case consts.Function_Domain: diff --git a/example.conf b/example.conf index 347e13f..4d99632 100644 --- a/example.conf +++ b/example.conf @@ -58,9 +58,9 @@ group { routing { #ip(geoip:private)->direct - !port(443) -> direct + !port(80) -> my_group sport(123) -> direct - !sip(192.168.0.252/30) -> direct + sip(192.168.0.0/24) && !sip(192.168.0.252/30) -> direct domain(geosite:category-ads) -> block l4proto(udp) && mac('02:42:ac:11:00:03') -> my_group domain(geosite:disney) -> disney diff --git a/go.mod b/go.mod index 50c2897..ca5de67 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/mzz2017/softwind v0.0.0-20230127172609-05c5264aa6a4 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.6.1 - github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230127154011-4f61520cc0b7 + github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230129030458-867b50f6cc67 github.com/v2rayA/shadowsocksR v1.0.4 github.com/vishvananda/netlink v1.1.0 golang.org/x/net v0.5.0 diff --git a/go.sum b/go.sum index 1c0e220..9cd696e 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230127154011-4f61520cc0b7 h1:o7BGW7hcNACMtpeXvXG9epG/2napoDGLluldZ0NE0XI= -github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230127154011-4f61520cc0b7/go.mod h1:JiTWeZybOkBfCqv/fy5jbFhXTxuLlyrI76gRNazz2sU= +github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230129030458-867b50f6cc67 h1:BKYTwtvnzg/QQG5uQmWNHDu07KmkrfdpZ98pAOvZf0g= +github.com/v2rayA/dae-config-dist/go/dae_config v0.0.0-20230129030458-867b50f6cc67/go.mod h1:JiTWeZybOkBfCqv/fy5jbFhXTxuLlyrI76gRNazz2sU= github.com/v2rayA/shadowsocksR v1.0.4 h1:65Ltdy+I/DnlkQTJj+R+X85zhZ63ORE1Roy+agAcF/s= github.com/v2rayA/shadowsocksR v1.0.4/go.mod h1:CyOhDLy8/AKedsi16xRYAMmkxSCH1ukJPaacaTdRfQg= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= diff --git a/pkg/config_parser/config_parser_test.go b/pkg/config_parser/config_parser_test.go index e4586d9..1a1da8e 100644 --- a/pkg/config_parser/config_parser_test.go +++ b/pkg/config_parser/config_parser_test.go @@ -74,6 +74,8 @@ group { } routing { + sip(192.168.0.0/24) && !sip(192.168.0.252/30) -> direct + domain(geosite:category-ads) -> block domain(geosite:disney) -> disney domain(geosite:netflix) -> netflix diff --git a/pkg/config_parser/section.go b/pkg/config_parser/section.go index 3b38f2e..1a9f59d 100644 --- a/pkg/config_parser/section.go +++ b/pkg/config_parser/section.go @@ -135,6 +135,9 @@ type Function struct { func (f *Function) String(compact bool) string { var builder strings.Builder + if f.Not { + builder.WriteString("!") + } builder.WriteString(f.Name + "(") var strParamList []string for _, p := range f.Params { @@ -181,27 +184,28 @@ type RoutingRule struct { func (r *RoutingRule) String(calcN bool) string { var builder strings.Builder var n int - for _, f := range r.AndFunctions { - if builder.Len() != 0 { + for i, f := range r.AndFunctions { + if i != 0 { builder.WriteString(" && ") } var paramBuilder strings.Builder n += len(f.Params) - for _, p := range f.Params { - if paramBuilder.Len() != 0 { - paramBuilder.WriteString(", ") - } - if p.Key != "" { - paramBuilder.WriteString(p.Key + ": " + p.Val) - } else { - paramBuilder.WriteString(p.Val) + if calcN { + paramBuilder.WriteString("[n = " + strconv.Itoa(n) + "]") + } else { + for j, param := range f.Params { + if j != 0 { + paramBuilder.WriteString(", ") + } + paramBuilder.WriteString(param.String(false)) } } - builder.WriteString(fmt.Sprintf("%v(%v)", f.Name, paramBuilder.String())) + symNot := "" + if f.Not { + symNot = "!" + } + builder.WriteString(fmt.Sprintf("%v%v(%v)", symNot, f.Name, paramBuilder.String())) } builder.WriteString(" -> " + r.Outbound) - if calcN { - builder.WriteString(" [n = " + strconv.Itoa(n) + "]") - } return builder.String() } diff --git a/pkg/config_parser/walker.go b/pkg/config_parser/walker.go index d12d495..dcdbc28 100644 --- a/pkg/config_parser/walker.go +++ b/pkg/config_parser/walker.go @@ -185,20 +185,16 @@ func (w *Walker) parseFunctionPrototypeExpression(ctx dae_config.IFunctionProtot func (w *Walker) parseRoutingRule(ctx dae_config.IRoutingRuleContext) *RoutingRule { children := ctx.GetChildren() //logrus.Debugln(ctx.GetText(), children) - left, ok := children[0].(*dae_config.RoutingRuleLeftContext) - if !ok { - w.ReportError(ctx, ErrorType_Unsupported, "not *RoutingRuleLeftContext: "+ctx.GetText()) - return nil - } - outbound := children[2].(*dae_config.Bare_literalContext).GetText() - // Parse functions. - children = left.GetChildren() - functionList, ok := children[1].(*dae_config.FunctionPrototypeExpressionContext) + functionList, ok := children[0].(*dae_config.FunctionPrototypeExpressionContext) if !ok { w.ReportError(ctx, ErrorType_Unsupported, "not *FunctionPrototypeExpressionContext: "+ctx.GetText()) return nil } + // Parse functions. andFunctions := w.parseFunctionPrototypeExpression(functionList, nil) + + // Parse outbound. + outbound := children[2].(*dae_config.Bare_literalContext).GetText() return &RoutingRule{ AndFunctions: andFunctions, Outbound: outbound,