feat: support as-is for dns_upstream

This commit is contained in:
mzz2017 2023-02-06 16:22:07 +08:00
parent e97b298577
commit 446a3993bc
8 changed files with 58 additions and 38 deletions

View File

@ -95,4 +95,6 @@ Note that if you bind dae to WAN only, dae only provide network service for loca
1. Log to userspace.
1. DNS upstream support tcp://
1. ...

View File

@ -289,16 +289,27 @@ retryLoadBpf:
}
// DNS upstream.
dnsAddrPort, err := netip.ParseAddrPort(dnsUpstream)
if err != nil {
return nil, fmt.Errorf("failed to parse DNS upstream: %v: %w", dnsUpstream, err)
}
dnsAddr16 := dnsAddrPort.Addr().As16()
if err = bpf.DnsUpstreamMap.Update(consts.ZeroKey, bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(dnsAddr16[:]),
Port: internal.Htons(dnsAddrPort.Port()),
}, ebpf.UpdateAny); err != nil {
return nil, err
var dnsAddrPort netip.AddrPort
if dnsUpstream != "" {
dnsAddrPort, err = netip.ParseAddrPort(dnsUpstream)
if err != nil {
return nil, fmt.Errorf("failed to parse DNS upstream: \"%v\": %w", dnsUpstream, err)
}
dnsAddr16 := dnsAddrPort.Addr().As16()
if err = bpf.DnsUpstreamMap.Update(consts.ZeroKey, bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(dnsAddr16[:]),
Port: internal.Htons(dnsAddrPort.Port()),
}, ebpf.UpdateAny); err != nil {
return nil, err
}
} else {
if err = bpf.DnsUpstreamMap.Update(consts.ZeroKey, bpfIpPort{
Ip: [4]uint32{},
// Zero port indicates no element, because bpf_map_lookup_elem cannot return 0 for map_type_array.
Port: 0,
}, ebpf.UpdateAny); err != nil {
return nil, err
}
}
return &ControlPlane{

View File

@ -6,6 +6,7 @@
package control
import (
"bytes"
"fmt"
"github.com/cilium/ebpf"
ciliumLink "github.com/cilium/ebpf/link"
@ -117,13 +118,14 @@ func (c *ControlPlaneCore) BindLan(ifname string) error {
return err
}
/// Insert ip rule / ip route.
if err = exec.Command("sh", "-c", `
var output []byte
if output, err = exec.Command("sh", "-c", `
ip rule add fwmark 0x80000000/0x80000000 table 2023
ip route add local 0.0.0.0/0 dev lo table 2023
ip -6 rule add fwmark 0x80000000/0x80000000 table 2023
ip -6 route add local ::/0 dev lo table 2023
`).Run(); err != nil {
return err
`).CombinedOutput(); err != nil {
return fmt.Errorf("%w: %v", err, string(bytes.TrimSpace(output)))
}
c.deferFuncs = append(c.deferFuncs, func() error {
return exec.Command("sh", "-c", `

View File

@ -914,9 +914,13 @@ routing(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
#define _is_wan flag[2]
int ret;
struct lpm_key lpm_key_instance, *lpm_key;
__u32 key = MatchType_L4Proto;
__u16 h_dport;
__u16 h_sport;
__u32 daddr[4];
/// TODO: BPF_MAP_UPDATE_BATCH ?
__u32 key = MatchType_L4Proto;
if (unlikely((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key,
&_l4proto_type, BPF_ANY)))) {
return ret;
@ -927,9 +931,7 @@ routing(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
return ret;
};
// Define variables for further use.
__u16 h_dport;
__u16 h_sport;
// Variables for further use.
if (_l4proto_type == L4ProtoType_TCP) {
h_dport = bpf_ntohs(((struct tcphdr *)l4hdr)->dest);
h_sport = bpf_ntohs(((struct tcphdr *)l4hdr)->source);
@ -950,22 +952,21 @@ routing(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
};
// Modify DNS upstream for routing.
__u32 daddr[4];
if (h_dport == 53 && _l4proto_type == L4ProtoType_UDP) {
struct ip_port *upstream =
bpf_map_lookup_elem(&dns_upstream_map, &zero_key);
if (unlikely(!upstream)) {
return -EFAULT;
if (upstream && upstream->port != 0) {
h_dport = bpf_ntohs(upstream->port);
__builtin_memcpy(daddr, upstream->ip, IPV6_BYTE_LENGTH);
} else {
__builtin_memcpy(daddr, _daddr, IPV6_BYTE_LENGTH);
}
h_dport = bpf_ntohs(upstream->port);
__builtin_memcpy(daddr, upstream->ip, IPV6_BYTE_LENGTH);
} else {
__builtin_memcpy(daddr, _daddr, IPV6_BYTE_LENGTH);
}
struct lpm_key lpm_key_instance, *lpm_key;
lpm_key_instance.trie_key.prefixlen = IPV6_BYTE_LENGTH * 8;
__builtin_memcpy(lpm_key_instance.data, daddr, IPV6_BYTE_LENGTH);
// bpf_printk("mac: %pI6", mac);
bpf_printk("daddr: %pI6", daddr);
key = MatchType_IpSet;
if (unlikely((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
BPF_ANY)))) {
@ -1138,7 +1139,6 @@ routing(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
#undef _is_wan
}
// Do DNAT.
SEC("tc/ingress")
int tproxy_lan_ingress(struct __sk_buff *skb) {
struct ethhdr ethh;
@ -1189,6 +1189,8 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
ip -6 rule del fwmark 0x80000000/0x80000000 table 1000
ip -6 route del local ::/0 dev lo table 1000
*/
// Socket lookup and assign skb to existing socket connection.
struct bpf_sock_tuple tuple = {0};
__u32 tuple_size;
if (ipversion == 4) {

View File

@ -102,7 +102,7 @@ func (c *ControlPlane) RelayToUDP(to netip.AddrPort, isDNS bool, dummyFrom *neti
if isDNS {
data, err = c.DnsRespHandler(data, validateRushAns)
if err != nil {
if errors.Is(err, SuspectedRushAnswerError) {
if validateRushAns && errors.Is(err, SuspectedRushAnswerError) {
// Reject DNS rush-answer.
c.log.WithFields(logrus.Fields{
"from": from,
@ -164,11 +164,13 @@ func (c *ControlPlane) handlePkt(data []byte, src, dst netip.AddrPort) (err erro
}
// Need to make a DNS request.
c.log.Tracef("Modify dns target %v to upstream: %v", RefineAddrPortToShow(destToSend), c.dnsUpstream)
// Modify dns target to upstream.
// NOTICE: Routing was calculated in advance by the eBPF program.
dummyFrom = &dst
destToSend = c.dnsUpstream
if c.dnsUpstream.IsValid() {
c.log.Tracef("Modify dns target %v to upstream: %v", RefineAddrPortToShow(destToSend), c.dnsUpstream)
// Modify dns target to upstream.
// NOTICE: Routing was calculated in advance by the eBPF program.
dummyFrom = &dst
destToSend = c.dnsUpstream
}
// Flip dns question to reduce dns pollution.
FlipDnsQuestionCase(dnsMessage)

View File

@ -98,18 +98,19 @@ func bindAddr(fd uintptr, addrPort netip.AddrPort) error {
var sockAddr syscall.Sockaddr
switch addr := addrPort.Addr().AsSlice(); len(addr) {
case 4:
addr := addrPort.Addr()
switch {
case addr.Is4() || addr.Is4In6():
a4 := &syscall.SockaddrInet4{
Port: int(addrPort.Port()),
}
copy(a4.Addr[:], addr)
a4.Addr = addr.As4()
sockAddr = a4
case 16:
case addr.Is6():
a6 := &syscall.SockaddrInet6{
Port: int(addrPort.Port()),
}
copy(a6.Addr[:], addr)
a6.Addr = addr.As16()
sockAddr = a6
default:
return fmt.Errorf("unexpected length of ip")

View File

@ -17,7 +17,7 @@ type Global struct {
LogLevel string `mapstructure:"log_level" default:"info"`
CheckUrl string `mapstructure:"check_url" default:"https://connectivitycheck.gstatic.com/generate_204"`
CheckInterval time.Duration `mapstructure:"check_interval" default:"15s"`
DnsUpstream string `mapstructure:"dns_upstream" default:"1.1.1.1:53"`
DnsUpstream string `mapstructure:"dns_upstream" require:""`
LanInterface []string `mapstructure:"lan_interface"`
WanInterface []string `mapstructure:"wan_interface"`
}

View File

@ -9,7 +9,7 @@ global {
check_url: 'https://connectivitycheck.gstatic.com/generate_204'
check_interval: 30s
# Now only support UDP and IP:Port.
# Now only support UDP and format IP:Port. Empty value '' indicates as-is.
# Please make sure DNS traffic will go through and be forwarded by dae.
# The upstream DNS answer MUST NOT be polluted.
# The request to dns upstream follows routing defined below.