mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-12 00:40:17 +07:00
feat: add more trace info (pid, pname, mac)
This commit is contained in:
@ -15,8 +15,6 @@ const (
|
|||||||
AppName = "dae"
|
AppName = "dae"
|
||||||
BpfPinRoot = "/sys/fs/bpf"
|
BpfPinRoot = "/sys/fs/bpf"
|
||||||
|
|
||||||
AddrHdrSize = 24
|
|
||||||
|
|
||||||
TaskCommLen = 16
|
TaskCommLen = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -393,3 +394,16 @@ func AddrToDnsType(addr netip.Addr) dnsmessage.Type {
|
|||||||
return dnsmessage.TypeAAAA
|
return dnsmessage.TypeAAAA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Htons converts the unsigned short integer hostshort from host byte order to network byte order.
|
||||||
|
func Htons(i uint16) uint16 {
|
||||||
|
b := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(b, i)
|
||||||
|
return *(*uint16)(unsafe.Pointer(&b[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ntohs converts the unsigned short integer hostshort from host byte order to network byte order.
|
||||||
|
func Ntohs(i uint16) uint16 {
|
||||||
|
bytes := *(*[2]byte)(unsafe.Pointer(&i))
|
||||||
|
return binary.BigEndian.Uint16(bytes[:])
|
||||||
|
}
|
||||||
|
@ -347,7 +347,7 @@ func (c *ControlPlane) finishInitDnsUpstreamResolve(raw common.UrlOrEmpty, dnsUp
|
|||||||
Ip6: common.Ipv6ByteSliceToUint32Array(ip6[:]),
|
Ip6: common.Ipv6ByteSliceToUint32Array(ip6[:]),
|
||||||
HasIp4: dnsUpstream.Ip4.IsValid(),
|
HasIp4: dnsUpstream.Ip4.IsValid(),
|
||||||
HasIp6: dnsUpstream.Ip6.IsValid(),
|
HasIp6: dnsUpstream.Ip6.IsValid(),
|
||||||
Port: internal.Htons(dnsUpstream.Port),
|
Port: common.Htons(dnsUpstream.Port),
|
||||||
}, ebpf.UpdateAny); err != nil {
|
}, ebpf.UpdateAny); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -485,7 +485,7 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Port.
|
// Port.
|
||||||
if err := c.core.bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(internal.Htons(port)), ebpf.UpdateAny); err != nil {
|
if err := c.core.bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(common.Htons(port)), ebpf.UpdateAny); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,16 +535,16 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
|||||||
// WAN. Old method.
|
// WAN. Old method.
|
||||||
addrHdr, dataOffset, err := ParseAddrHdr(data)
|
addrHdr, dataOffset, err := ParseAddrHdr(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Warnf("No AddrPort presented")
|
c.log.Warnf("No AddrPort presented: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(data, data[dataOffset:])
|
copy(data, data[dataOffset:])
|
||||||
routingResult = &bpfRoutingResult{
|
routingResult = &addrHdr.RoutingResult
|
||||||
Mark: addrHdr.Mark,
|
__ip := common.Ipv6Uint32ArrayToByteSlice(addrHdr.Ip)
|
||||||
Outbound: addrHdr.Outbound,
|
_ip, _ := netip.AddrFromSlice(__ip)
|
||||||
}
|
// Comment it because them SHOULD equal.
|
||||||
src = netip.AddrPortFrom(addrHdr.Dest.Addr(), src.Port())
|
//src = netip.AddrPortFrom(_ip, src.Port())
|
||||||
realDst = addrHdr.Dest
|
realDst = netip.AddrPortFrom(_ip, addrHdr.Port)
|
||||||
} else {
|
} else {
|
||||||
realDst = pktDst
|
realDst = pktDst
|
||||||
}
|
}
|
||||||
|
@ -127,12 +127,18 @@ struct ip_port {
|
|||||||
__be16 port;
|
__be16 port;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ip_port_outbound {
|
struct routing_result {
|
||||||
|
__u32 mark;
|
||||||
|
__u8 mac[6];
|
||||||
|
__u8 outbound;
|
||||||
|
__u8 pname[TASK_COMM_LEN];
|
||||||
|
__u32 pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dst_routing_result {
|
||||||
__be32 ip[4];
|
__be32 ip[4];
|
||||||
__be16 port;
|
__be16 port;
|
||||||
__u8 outbound;
|
struct routing_result routing_result;
|
||||||
__u8 unused;
|
|
||||||
__u32 mark;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tuples {
|
struct tuples {
|
||||||
@ -150,18 +156,13 @@ struct {
|
|||||||
// (source ip, source port, tcp) is
|
// (source ip, source port, tcp) is
|
||||||
// enough for identifier. And UDP client
|
// enough for identifier. And UDP client
|
||||||
// side does not care it (full-cone).
|
// side does not care it (full-cone).
|
||||||
__type(value, struct ip_port_outbound); // Original target.
|
__type(value, struct dst_routing_result); // Original target.
|
||||||
__uint(max_entries, MAX_DST_MAPPING_NUM);
|
__uint(max_entries, MAX_DST_MAPPING_NUM);
|
||||||
/// NOTICE: It MUST be pinned.
|
/// NOTICE: It MUST be pinned.
|
||||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||||
} tcp_dst_map
|
} tcp_dst_map
|
||||||
SEC(".maps"); // This map is only for old method (redirect mode in WAN).
|
SEC(".maps"); // This map is only for old method (redirect mode in WAN).
|
||||||
|
|
||||||
struct routing_result {
|
|
||||||
__u32 mark;
|
|
||||||
__u8 outbound;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||||
__type(key, struct tuples);
|
__type(key, struct tuples);
|
||||||
@ -1180,8 +1181,8 @@ routing(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool __always_inline is_not_to_lan(void *_ori_src) {
|
static bool __always_inline is_not_to_lan(void *_ori_src) {
|
||||||
struct ip_port_outbound *ori_src = _ori_src;
|
struct dst_routing_result *ori_src = _ori_src;
|
||||||
return ori_src->outbound == IS_WAN;
|
return ori_src->routing_result.outbound == IS_WAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SNAT for UDP packet.
|
// SNAT for UDP packet.
|
||||||
@ -1218,7 +1219,7 @@ int tproxy_lan_egress(struct __sk_buff *skb) {
|
|||||||
return TC_ACT_PIPE;
|
return TC_ACT_PIPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ip_port_outbound ori_src;
|
struct dst_routing_result ori_src;
|
||||||
if ((ret = decap_after_udp_hdr(skb, ipversion, ihl,
|
if ((ret = decap_after_udp_hdr(skb, ipversion, ihl,
|
||||||
ipversion == 4 ? iph.tot_len : 0, &ori_src,
|
ipversion == 4 ? iph.tot_len : 0, &ori_src,
|
||||||
sizeof(ori_src), is_not_to_lan, true))) {
|
sizeof(ori_src), is_not_to_lan, true))) {
|
||||||
@ -1347,6 +1348,10 @@ new_connection:
|
|||||||
struct routing_result routing_result = {0};
|
struct routing_result routing_result = {0};
|
||||||
routing_result.outbound = ret;
|
routing_result.outbound = ret;
|
||||||
routing_result.mark = ret >> 8;
|
routing_result.mark = ret >> 8;
|
||||||
|
__builtin_memcpy(routing_result.mac, ethh.h_source,
|
||||||
|
sizeof(routing_result.mac));
|
||||||
|
// No pid pname info in LAN.
|
||||||
|
|
||||||
// Save routing result.
|
// Save routing result.
|
||||||
if ((ret = bpf_map_update_elem(&routing_tuples_map, &tuples, &routing_result,
|
if ((ret = bpf_map_update_elem(&routing_tuples_map, &tuples, &routing_result,
|
||||||
BPF_ANY))) {
|
BPF_ANY))) {
|
||||||
@ -1597,6 +1602,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
key_src.port = tcph.source;
|
key_src.port = tcph.source;
|
||||||
__u8 outbound;
|
__u8 outbound;
|
||||||
__u32 mark;
|
__u32 mark;
|
||||||
|
struct pid_pname *pid_pname = NULL;
|
||||||
if (unlikely(tcp_state_syn)) {
|
if (unlikely(tcp_state_syn)) {
|
||||||
// New TCP connection.
|
// New TCP connection.
|
||||||
// bpf_printk("[%X]New Connection", bpf_ntohl(tcph.seq));
|
// bpf_printk("[%X]New Connection", bpf_ntohl(tcph.seq));
|
||||||
@ -1606,7 +1612,6 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
} else {
|
} else {
|
||||||
flag[1] = IpVersionType_4;
|
flag[1] = IpVersionType_4;
|
||||||
}
|
}
|
||||||
struct pid_pname *pid_pname;
|
|
||||||
if (pid_is_control_plane(skb, &pid_pname)) {
|
if (pid_is_control_plane(skb, &pid_pname)) {
|
||||||
// From control plane. Direct.
|
// From control plane. Direct.
|
||||||
return TC_ACT_OK;
|
return TC_ACT_OK;
|
||||||
@ -1641,14 +1646,14 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
} else {
|
} else {
|
||||||
// bpf_printk("[%X]Old Connection", bpf_ntohl(tcph.seq));
|
// bpf_printk("[%X]Old Connection", bpf_ntohl(tcph.seq));
|
||||||
// The TCP connection exists.
|
// The TCP connection exists.
|
||||||
struct ip_port_outbound *dst =
|
struct dst_routing_result *dst =
|
||||||
bpf_map_lookup_elem(&tcp_dst_map, &key_src);
|
bpf_map_lookup_elem(&tcp_dst_map, &key_src);
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
// Do not impact previous connections.
|
// Do not impact previous connections.
|
||||||
return TC_ACT_OK;
|
return TC_ACT_OK;
|
||||||
}
|
}
|
||||||
outbound = dst->outbound;
|
outbound = dst->routing_result.outbound;
|
||||||
mark = dst->mark;
|
mark = dst->routing_result.mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((outbound == OUTBOUND_DIRECT || outbound == OUTBOUND_MUST_DIRECT) &&
|
if ((outbound == OUTBOUND_DIRECT || outbound == OUTBOUND_MUST_DIRECT) &&
|
||||||
@ -1675,15 +1680,22 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(tcp_state_syn)) {
|
if (unlikely(tcp_state_syn)) {
|
||||||
struct ip_port_outbound value_dst;
|
struct dst_routing_result routing_info;
|
||||||
__builtin_memset(&value_dst, 0, sizeof(value_dst));
|
__builtin_memset(&routing_info, 0, sizeof(routing_info));
|
||||||
__builtin_memcpy(value_dst.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
__builtin_memcpy(routing_info.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
||||||
value_dst.port = tcph.dest;
|
routing_info.port = tcph.dest;
|
||||||
value_dst.outbound = outbound;
|
routing_info.routing_result.outbound = outbound;
|
||||||
value_dst.mark = mark;
|
routing_info.routing_result.mark = mark;
|
||||||
|
__builtin_memcpy(routing_info.routing_result.mac, ethh.h_source,
|
||||||
|
sizeof(ethh.h_source));
|
||||||
|
if (pid_pname) {
|
||||||
|
__builtin_memcpy(routing_info.routing_result.pname, pid_pname->pname,
|
||||||
|
TASK_COMM_LEN);
|
||||||
|
routing_info.routing_result.pid = pid_pname->pid;
|
||||||
|
}
|
||||||
// bpf_printk("UPDATE: %pI6:%u", key_src.ip.u6_addr32,
|
// bpf_printk("UPDATE: %pI6:%u", key_src.ip.u6_addr32,
|
||||||
// bpf_ntohs(key_src.port));
|
// bpf_ntohs(key_src.port));
|
||||||
bpf_map_update_elem(&tcp_dst_map, &key_src, &value_dst, BPF_ANY);
|
bpf_map_update_elem(&tcp_dst_map, &key_src, &routing_info, BPF_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write mac.
|
// Write mac.
|
||||||
@ -1699,11 +1711,6 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} else if (l4proto == IPPROTO_UDP) {
|
} else if (l4proto == IPPROTO_UDP) {
|
||||||
// Backup for further use.
|
|
||||||
struct ip_port_outbound new_hdr;
|
|
||||||
__builtin_memset(&new_hdr, 0, sizeof(new_hdr));
|
|
||||||
__builtin_memcpy(new_hdr.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
|
||||||
new_hdr.port = udph.dest;
|
|
||||||
|
|
||||||
// Routing. It decides if we redirect traffic to control plane.
|
// Routing. It decides if we redirect traffic to control plane.
|
||||||
__u32 flag[6] = {L4ProtoType_UDP};
|
__u32 flag[6] = {L4ProtoType_UDP};
|
||||||
@ -1732,8 +1739,20 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
bpf_printk("shot routing: %d", ret);
|
bpf_printk("shot routing: %d", ret);
|
||||||
return TC_ACT_SHOT;
|
return TC_ACT_SHOT;
|
||||||
}
|
}
|
||||||
new_hdr.outbound = ret;
|
// Construct new hdr to encap.
|
||||||
new_hdr.mark = ret >> 8;
|
struct dst_routing_result new_hdr;
|
||||||
|
__builtin_memset(&new_hdr, 0, sizeof(new_hdr));
|
||||||
|
__builtin_memcpy(new_hdr.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
||||||
|
new_hdr.port = udph.dest;
|
||||||
|
new_hdr.routing_result.outbound = ret;
|
||||||
|
new_hdr.routing_result.mark = ret >> 8;
|
||||||
|
__builtin_memcpy(new_hdr.routing_result.mac, ethh.h_source,
|
||||||
|
sizeof(ethh.h_source));
|
||||||
|
if (pid_pname) {
|
||||||
|
__builtin_memcpy(new_hdr.routing_result.pname, pid_pname->pname,
|
||||||
|
TASK_COMM_LEN);
|
||||||
|
new_hdr.routing_result.pid = pid_pname->pid;
|
||||||
|
}
|
||||||
#if defined(__DEBUG_ROUTING) || defined(__PRINT_ROUTING_RESULT)
|
#if defined(__DEBUG_ROUTING) || defined(__PRINT_ROUTING_RESULT)
|
||||||
__u32 pid = pid_pname ? pid_pname->pid : 0;
|
__u32 pid = pid_pname ? pid_pname->pid : 0;
|
||||||
bpf_printk("udp(wan): from %pI6:%u [PID %u]", tuples.sip.u6_addr32,
|
bpf_printk("udp(wan): from %pI6:%u [PID %u]", tuples.sip.u6_addr32,
|
||||||
@ -1742,13 +1761,13 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
tuples.dip.u6_addr32, bpf_ntohs(tuples.dport));
|
tuples.dip.u6_addr32, bpf_ntohs(tuples.dport));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((new_hdr.outbound == OUTBOUND_DIRECT ||
|
if ((new_hdr.routing_result.outbound == OUTBOUND_DIRECT ||
|
||||||
new_hdr.outbound == OUTBOUND_MUST_DIRECT) &&
|
new_hdr.routing_result.outbound == OUTBOUND_MUST_DIRECT) &&
|
||||||
new_hdr.mark == 0 // If mark is not zero, we should re-route it, so we
|
new_hdr.routing_result.mark == 0 // If mark is not zero, we should re-route it, so we
|
||||||
// send it to control plane in WAN.
|
// send it to control plane in WAN.
|
||||||
) {
|
) {
|
||||||
return TC_ACT_OK;
|
return TC_ACT_OK;
|
||||||
} else if (unlikely(new_hdr.outbound == OUTBOUND_BLOCK)) {
|
} else if (unlikely(new_hdr.routing_result.outbound == OUTBOUND_BLOCK)) {
|
||||||
return TC_ACT_SHOT;
|
return TC_ACT_SHOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1756,7 +1775,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
|||||||
|
|
||||||
// Check outbound connectivity in specific ipversion and l4proto.
|
// Check outbound connectivity in specific ipversion and l4proto.
|
||||||
struct outbound_connectivity_query q = {0};
|
struct outbound_connectivity_query q = {0};
|
||||||
q.outbound = new_hdr.outbound;
|
q.outbound = new_hdr.routing_result.outbound;
|
||||||
q.ipversion = ipversion;
|
q.ipversion = ipversion;
|
||||||
q.l4proto = l4proto;
|
q.l4proto = l4proto;
|
||||||
__u32 *alive;
|
__u32 *alive;
|
||||||
@ -1892,7 +1911,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
|||||||
// map element using income client ip (that is daddr).
|
// map element using income client ip (that is daddr).
|
||||||
__builtin_memcpy(&key_dst.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
__builtin_memcpy(&key_dst.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
||||||
key_dst.port = tcph.dest;
|
key_dst.port = tcph.dest;
|
||||||
struct ip_port_outbound *original_dst =
|
struct dst_routing_result *original_dst =
|
||||||
bpf_map_lookup_elem(&tcp_dst_map, &key_dst);
|
bpf_map_lookup_elem(&tcp_dst_map, &key_dst);
|
||||||
if (!original_dst) {
|
if (!original_dst) {
|
||||||
bpf_printk("[%X]Bad Connection: to: %pI6:%u", bpf_ntohl(tcph.seq),
|
bpf_printk("[%X]Bad Connection: to: %pI6:%u", bpf_ntohl(tcph.seq),
|
||||||
@ -1917,7 +1936,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
|||||||
/// NOTICE: Actually, we do not need symmetrical headers in client and
|
/// NOTICE: Actually, we do not need symmetrical headers in client and
|
||||||
/// server. We use it for convinience. This behavior may change in the
|
/// server. We use it for convinience. This behavior may change in the
|
||||||
/// future. Outbound here is useless and redundant.
|
/// future. Outbound here is useless and redundant.
|
||||||
struct ip_port_outbound ori_src;
|
struct dst_routing_result ori_src;
|
||||||
|
|
||||||
// Get source ip/port from our packet header.
|
// Get source ip/port from our packet header.
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/v2rayA/dae/common/consts"
|
"github.com/v2rayA/dae/common/consts"
|
||||||
"github.com/v2rayA/dae/component/outbound/dialer"
|
"github.com/v2rayA/dae/component/outbound/dialer"
|
||||||
"github.com/v2rayA/dae/component/sniffing"
|
"github.com/v2rayA/dae/component/sniffing"
|
||||||
internal "github.com/v2rayA/dae/pkg/ebpf_internal"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -44,24 +43,21 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
|||||||
routingResult, err := c.core.RetrieveRoutingResult(src, dst, unix.IPPROTO_TCP)
|
routingResult, err := c.core.RetrieveRoutingResult(src, dst, unix.IPPROTO_TCP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// WAN. Old method.
|
// WAN. Old method.
|
||||||
var value bpfIpPortOutbound
|
var value bpfDstRoutingResult
|
||||||
ip6 := src.Addr().As16()
|
ip6 := src.Addr().As16()
|
||||||
if e := c.core.bpf.TcpDstMap.Lookup(bpfIpPort{
|
if e := c.core.bpf.TcpDstMap.Lookup(bpfIpPort{
|
||||||
Ip: struct{ U6Addr8 [16]uint8 }{U6Addr8: ip6},
|
Ip: struct{ U6Addr8 [16]uint8 }{U6Addr8: ip6},
|
||||||
Port: internal.Htons(src.Port()),
|
Port: common.Htons(src.Port()),
|
||||||
}, &value); e != nil {
|
}, &value); e != nil {
|
||||||
return fmt.Errorf("failed to retrieve target info %v: %v, %v", src.String(), err, e)
|
return fmt.Errorf("failed to retrieve target info %v: %v, %v", src.String(), err, e)
|
||||||
}
|
}
|
||||||
routingResult = &bpfRoutingResult{
|
routingResult = &value.RoutingResult
|
||||||
Mark: value.Mark,
|
|
||||||
Outbound: value.Outbound,
|
|
||||||
}
|
|
||||||
|
|
||||||
dstAddr, ok := netip.AddrFromSlice(common.Ipv6Uint32ArrayToByteSlice(value.Ip))
|
dstAddr, ok := netip.AddrFromSlice(common.Ipv6Uint32ArrayToByteSlice(value.Ip))
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("failed to parse dest ip: %v", value.Ip)
|
return fmt.Errorf("failed to parse dest ip: %v", value.Ip)
|
||||||
}
|
}
|
||||||
dst = netip.AddrPortFrom(dstAddr, internal.Htons(value.Port))
|
dst = netip.AddrPortFrom(dstAddr, common.Htons(value.Port))
|
||||||
}
|
}
|
||||||
var outboundIndex = consts.OutboundIndex(routingResult.Outbound)
|
var outboundIndex = consts.OutboundIndex(routingResult.Outbound)
|
||||||
|
|
||||||
@ -101,6 +97,9 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
|||||||
"policy": outbound.GetSelectionPolicy(),
|
"policy": outbound.GetSelectionPolicy(),
|
||||||
"dialer": d.Name(),
|
"dialer": d.Name(),
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
|
"pid": routingResult.Pid,
|
||||||
|
"pname": ProcessName2String(routingResult.Pname[:]),
|
||||||
|
"mac": Mac2String(routingResult.Mac[:]),
|
||||||
}).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), RefineAddrPortToShow(dst))
|
}).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), RefineAddrPortToShow(dst))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,10 @@ package control
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/mzz2017/softwind/pkg/zeroalloc/buffer"
|
||||||
"github.com/mzz2017/softwind/pool"
|
"github.com/mzz2017/softwind/pool"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/v2rayA/dae/common"
|
"github.com/v2rayA/dae/common"
|
||||||
@ -22,6 +24,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -44,52 +47,32 @@ func ChooseNatTimeout(data []byte, sniffDns bool) (dmsg *dnsmessage.Message, tim
|
|||||||
return nil, DefaultNatTimeout
|
return nil, DefaultNatTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddrHdr struct {
|
func ParseAddrHdr(data []byte) (hdr *bpfDstRoutingResult, dataOffset int, err error) {
|
||||||
Dest netip.AddrPort
|
dataOffset = int(unsafe.Sizeof(bpfDstRoutingResult{}))
|
||||||
Outbound uint8
|
|
||||||
Mark uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseAddrHdr(data []byte) (hdr *AddrHdr, dataOffset int, err error) {
|
|
||||||
ipSize := 16
|
|
||||||
dataOffset = consts.AddrHdrSize
|
|
||||||
if len(data) < dataOffset {
|
if len(data) < dataOffset {
|
||||||
return nil, 0, fmt.Errorf("data is too short to parse AddrHdr")
|
return nil, 0, fmt.Errorf("data is too short to parse AddrHdr")
|
||||||
}
|
}
|
||||||
destAddr, _ := netip.AddrFromSlice(data[:ipSize])
|
_hdr := *(*bpfDstRoutingResult)(unsafe.Pointer(&data[0]))
|
||||||
port := binary.BigEndian.Uint16(data[ipSize:])
|
_hdr.Port = common.Ntohs(_hdr.Port)
|
||||||
outbound := data[ipSize+2]
|
return &_hdr, dataOffset, nil
|
||||||
mark := binary.BigEndian.Uint32(data[ipSize+4:])
|
|
||||||
return &AddrHdr{
|
|
||||||
Dest: netip.AddrPortFrom(destAddr, port),
|
|
||||||
Outbound: outbound,
|
|
||||||
Mark: mark,
|
|
||||||
}, dataOffset, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hdr *AddrHdr) ToBytesFromPool() []byte {
|
|
||||||
ipSize := 16
|
|
||||||
buf := pool.GetZero(consts.AddrHdrSize) // byte align to a multiple of 4
|
|
||||||
ip := hdr.Dest.Addr().As16()
|
|
||||||
copy(buf, ip[:])
|
|
||||||
binary.BigEndian.PutUint16(buf[ipSize:], hdr.Dest.Port())
|
|
||||||
buf[ipSize+2] = hdr.Outbound
|
|
||||||
binary.BigEndian.PutUint32(buf[ipSize+4:], hdr.Mark)
|
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendPktWithHdrWithFlag(data []byte, mark uint32, from netip.AddrPort, lConn *net.UDPConn, to netip.AddrPort, lanWanFlag consts.LanWanFlag) error {
|
func sendPktWithHdrWithFlag(data []byte, mark uint32, from netip.AddrPort, lConn *net.UDPConn, to netip.AddrPort, lanWanFlag consts.LanWanFlag) error {
|
||||||
hdr := AddrHdr{
|
hdr := bpfDstRoutingResult{
|
||||||
Dest: from,
|
Ip: common.Ipv6ByteSliceToUint32Array(from.Addr().AsSlice()),
|
||||||
Mark: mark,
|
Port: common.Htons(from.Port()),
|
||||||
Outbound: uint8(lanWanFlag), // Pass some message to the kernel program.
|
RoutingResult: bpfRoutingResult{
|
||||||
|
Outbound: uint8(lanWanFlag), // Pass some message to the kernel program.
|
||||||
|
},
|
||||||
}
|
}
|
||||||
bHdr := hdr.ToBytesFromPool()
|
buf := pool.Get(int(unsafe.Sizeof(hdr)) + len(data))
|
||||||
defer pool.Put(bHdr)
|
|
||||||
buf := pool.Get(len(bHdr) + len(data))
|
|
||||||
defer pool.Put(buf)
|
defer pool.Put(buf)
|
||||||
copy(buf, bHdr)
|
b := buffer.NewBufferFrom(buf)
|
||||||
copy(buf[len(bHdr):], data)
|
defer b.Put()
|
||||||
|
if err := gob.NewEncoder(b).Encode(&hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
copy(buf[int(unsafe.Sizeof(hdr)):], data)
|
||||||
//log.Println("from", from, "to", to)
|
//log.Println("from", from, "to", to)
|
||||||
_, err := lConn.WriteToUDPAddrPort(buf, to)
|
_, err := lConn.WriteToUDPAddrPort(buf, to)
|
||||||
return err
|
return err
|
||||||
@ -368,6 +351,9 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
|
|||||||
c.log.WithFields(logrus.Fields{
|
c.log.WithFields(logrus.Fields{
|
||||||
"to": destToSend.String(),
|
"to": destToSend.String(),
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
|
"pid": routingResult.Pid,
|
||||||
|
"pname": ProcessName2String(routingResult.Pname[:]),
|
||||||
|
"mac": Mac2String(routingResult.Mac[:]),
|
||||||
"from": realSrc.String(),
|
"from": realSrc.String(),
|
||||||
"network": networkType.String(),
|
"network": networkType.String(),
|
||||||
"err": err.Error(),
|
"err": err.Error(),
|
||||||
@ -439,16 +425,25 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
|
|||||||
"dialer": realDialer.Name(),
|
"dialer": realDialer.Name(),
|
||||||
"qname": strings.ToLower(q.Name.String()),
|
"qname": strings.ToLower(q.Name.String()),
|
||||||
"qtype": q.Type,
|
"qtype": q.Type,
|
||||||
|
"pid": routingResult.Pid,
|
||||||
|
"pname": ProcessName2String(routingResult.Pname[:]),
|
||||||
|
"mac": Mac2String(routingResult.Mac[:]),
|
||||||
}).Infof("%v <-> %v",
|
}).Infof("%v <-> %v",
|
||||||
RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend),
|
RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend),
|
||||||
)
|
)
|
||||||
} else if c.log.IsLevelEnabled(logrus.InfoLevel) {
|
} else if c.log.IsLevelEnabled(logrus.InfoLevel) {
|
||||||
|
if isDns && len(dnsMessage.Questions) > 0 {
|
||||||
|
domain = strings.ToLower(dnsMessage.Questions[0].Name.String())
|
||||||
|
}
|
||||||
c.log.WithFields(logrus.Fields{
|
c.log.WithFields(logrus.Fields{
|
||||||
"network": string(l4proto) + string(ipversion),
|
"network": string(l4proto) + string(ipversion),
|
||||||
"outbound": outbound.Name,
|
"outbound": outbound.Name,
|
||||||
"policy": outbound.GetSelectionPolicy(),
|
"policy": outbound.GetSelectionPolicy(),
|
||||||
"dialer": realDialer.Name(),
|
"dialer": realDialer.Name(),
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
|
"pid": routingResult.Pid,
|
||||||
|
"pname": ProcessName2String(routingResult.Pname[:]),
|
||||||
|
"mac": Mac2String(routingResult.Mac[:]),
|
||||||
}).Infof("%v <-> %v",
|
}).Infof("%v <-> %v",
|
||||||
RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend),
|
RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend),
|
||||||
)
|
)
|
||||||
|
@ -8,10 +8,11 @@ package control
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mzz2017/softwind/netproxy"
|
"github.com/mzz2017/softwind/netproxy"
|
||||||
|
"github.com/v2rayA/dae/common"
|
||||||
"github.com/v2rayA/dae/common/consts"
|
"github.com/v2rayA/dae/common/consts"
|
||||||
internal "github.com/v2rayA/dae/pkg/ebpf_internal"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
@ -24,14 +25,14 @@ func (c *ControlPlaneCore) RetrieveRoutingResult(src, dst netip.AddrPort, l4prot
|
|||||||
|
|
||||||
tuples := &bpfTuples{
|
tuples := &bpfTuples{
|
||||||
Sip: struct{ U6Addr8 [16]uint8 }{U6Addr8: srcIp6},
|
Sip: struct{ U6Addr8 [16]uint8 }{U6Addr8: srcIp6},
|
||||||
Sport: internal.Htons(src.Port()),
|
Sport: common.Htons(src.Port()),
|
||||||
Dip: struct{ U6Addr8 [16]uint8 }{U6Addr8: dstIp6},
|
Dip: struct{ U6Addr8 [16]uint8 }{U6Addr8: dstIp6},
|
||||||
Dport: internal.Htons(dst.Port()),
|
Dport: common.Htons(dst.Port()),
|
||||||
L4proto: l4proto,
|
L4proto: l4proto,
|
||||||
}
|
}
|
||||||
|
|
||||||
var routingResult bpfRoutingResult
|
var routingResult bpfRoutingResult
|
||||||
if err := c.bpf.RoutingTuplesMap.Lookup(tuples, &routingResult); err != nil {
|
if err := c.bpf.RoutingTuplesMap.LookupAndDelete(tuples, &routingResult); err != nil {
|
||||||
return nil, fmt.Errorf("reading map: key [%v, %v, %v]: %w", src.String(), l4proto, dst.String(), err)
|
return nil, fmt.Errorf("reading map: key [%v, %v, %v]: %w", src.String(), l4proto, dst.String(), err)
|
||||||
}
|
}
|
||||||
return &routingResult, nil
|
return &routingResult, nil
|
||||||
@ -88,3 +89,18 @@ func GetNetwork(network string, mark uint32) string {
|
|||||||
}.Encode()
|
}.Encode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProcessName2String(pname []uint8) string {
|
||||||
|
return string(bytes.TrimRight(pname[:], string([]byte{0})))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Mac2String(mac []uint8) string {
|
||||||
|
ori := []byte(hex.EncodeToString(mac))
|
||||||
|
// Insert ":".
|
||||||
|
b := make([]byte, len(ori)/2*3)
|
||||||
|
for i, j := 0, 0; i < len(ori); i, j = i+2, j+3 {
|
||||||
|
copy(b[j:j+2], ori[i:i+2])
|
||||||
|
b[j+2] = ':'
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
@ -3,29 +3,21 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"github.com/v2rayA/dae/common"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func OpenRawSock(index int) (int, error) {
|
func OpenRawSock(index int) (int, error) {
|
||||||
sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, int(Htons(syscall.ETH_P_ALL)))
|
sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, int(common.Htons(syscall.ETH_P_ALL)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
sll := syscall.SockaddrLinklayer{
|
sll := syscall.SockaddrLinklayer{
|
||||||
Ifindex: index,
|
Ifindex: index,
|
||||||
Protocol: Htons(syscall.ETH_P_ALL),
|
Protocol: common.Htons(syscall.ETH_P_ALL),
|
||||||
}
|
}
|
||||||
if err := syscall.Bind(sock, &sll); err != nil {
|
if err := syscall.Bind(sock, &sll); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return sock, nil
|
return sock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Htons converts the unsigned short integer hostshort from host byte order to network byte order.
|
|
||||||
func Htons(i uint16) uint16 {
|
|
||||||
b := make([]byte, 2)
|
|
||||||
binary.BigEndian.PutUint16(b, i)
|
|
||||||
return *(*uint16)(unsafe.Pointer(&b[0]))
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user