mirror of
https://github.com/daeuniverse/dae.git
synced 2025-01-31 01:44:50 +07:00
feat: support as-is for dns_upstream
This commit is contained in:
parent
e97b298577
commit
446a3993bc
@ -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. ...
|
||||
|
@ -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{
|
||||
|
@ -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", `
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user