Skip to content

Commit 1569efa

Browse files
committed
dns name
1 parent e9ebab7 commit 1569efa

18 files changed

+201
-43
lines changed

.mk/bc.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ define MAPS
3434
"additional_flow_metrics":"per_cpu_hash",
3535
"packet_record":"ringbuf",
3636
"dns_flows":"hash",
37+
"dns_parse_buffer_map":"percpu_array",
3738
"global_counters":"per_cpu_array",
3839
"filter_map":"lpm_trie",
3940
"peer_filter_map":"lpm_trie",

bpf/dns_tracker.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,22 @@
88

99
#define DNS_DEFAULT_PORT 53
1010
#define DNS_QR_FLAG 0x8000
11+
#define DNS_OPCODE_MASK 0x7800
12+
#define DNS_RCODE_MASK 0x0F
1113
#define UDP_MAXMSG 512
1214

15+
// Per-CPU buffer for DNS name parsing to avoid stack overflow
16+
struct dns_parse_buffer {
17+
char name[DNS_NAME_MAX_LEN];
18+
};
19+
20+
struct {
21+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
22+
__uint(max_entries, 1);
23+
__type(key, u32);
24+
__type(value, struct dns_parse_buffer);
25+
} dns_parse_buffer_map SEC(".maps");
26+
1327
// See https://www.rfc-editor.org/rfc/rfc1035 4.1.1. Header section format
1428
struct dns_header {
1529
u16 id;
@@ -65,7 +79,7 @@ static __always_inline u8 calc_dns_header_offset(pkt_info *pkt, void *data_end)
6579
return len;
6680
}
6781

68-
static __always_inline int track_dns_packet(struct __sk_buff *skb, pkt_info *pkt) {
82+
static __noinline int track_dns_packet(struct __sk_buff *skb, pkt_info *pkt) {
6983
void *data_end = (void *)(long)skb->data_end;
7084
int ret = 0;
7185
if (pkt->id->dst_port == dns_port || pkt->id->src_port == dns_port ||
@@ -108,6 +122,19 @@ static __always_inline int track_dns_packet(struct __sk_buff *skb, pkt_info *pkt
108122
}
109123
pkt->dns_id = dns_id;
110124
pkt->dns_flags = flags;
125+
126+
// Parse DNS QNAME using per-CPU buffer
127+
u32 key = 0;
128+
struct dns_parse_buffer *buf = bpf_map_lookup_elem(&dns_parse_buffer_map, &key);
129+
if (buf) {
130+
// Copy raw QNAME bytes (label-encoded) and let userspace decode to dotted form
131+
__builtin_memset(buf->name, 0, DNS_NAME_MAX_LEN);
132+
u32 qname_off = dns_offset + sizeof(struct dns_header);
133+
// Best-effort fixed-size copy; safe for verifier (constant size)
134+
(void)bpf_skb_load_bytes(skb, qname_off, buf->name, DNS_NAME_MAX_LEN - 1);
135+
// Ensure null-termination
136+
buf->name[DNS_NAME_MAX_LEN - 1] = '\0';
137+
}
111138
} // end of dns response
112139
}
113140
return ret;

bpf/flows.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ static inline void update_dns(additional_metrics *extra_metrics, pkt_info *pkt,
118118
extra_metrics->dns_record.id = pkt->dns_id;
119119
extra_metrics->dns_record.flags = pkt->dns_flags;
120120
extra_metrics->dns_record.latency = pkt->dns_latency;
121+
122+
// Copy DNS name from per-CPU buffer if available
123+
u32 key = 0;
124+
struct dns_parse_buffer *buf = bpf_map_lookup_elem(&dns_parse_buffer_map, &key);
125+
if (buf) {
126+
__builtin_memcpy(extra_metrics->dns_record.name, buf->name, DNS_NAME_MAX_LEN);
127+
}
121128
}
122129
if (dns_errno != 0) {
123130
extra_metrics->dns_record.errno = dns_errno;
@@ -254,6 +261,13 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
254261
new_metrics.dns_record.flags = pkt.dns_flags;
255262
new_metrics.dns_record.latency = pkt.dns_latency;
256263
new_metrics.dns_record.errno = dns_errno;
264+
265+
// Copy DNS name from per-CPU buffer if available
266+
u32 key = 0;
267+
struct dns_parse_buffer *buf = bpf_map_lookup_elem(&dns_parse_buffer_map, &key);
268+
if (buf) {
269+
__builtin_memcpy(new_metrics.dns_record.name, buf->name, DNS_NAME_MAX_LEN);
270+
}
257271
long ret =
258272
bpf_map_update_elem(&additional_flow_metrics, &id, &new_metrics, BPF_NOEXIST);
259273
if (ret != 0) {

bpf/types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ typedef __u64 u64;
7070
#define OBSERVED_DIRECTION_BOTH 3
7171

7272
#define MAX_PAYLOAD_SIZE 256
73+
#define DNS_NAME_MAX_LEN 32
7374

7475
// according to field 61 in https://www.iana.org/assignments/ipfix/ipfix.xhtml
7576
typedef enum direction_t {
@@ -123,6 +124,7 @@ typedef struct additional_metrics_t {
123124
u16 id;
124125
u16 flags;
125126
u8 errno;
127+
char name[DNS_NAME_MAX_LEN];
126128
} dns_record;
127129
struct pkt_drops_t {
128130
u64 bytes;

pkg/decode/decode_protobuf.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,46 @@ const (
2626
type Protobuf struct {
2727
}
2828

29+
// dnsRawNameToDotted parses a label-encoded DNS QNAME (raw bytes copied from kernel)
30+
// into a dotted string. Stops on NUL, compression pointer, or bounds.
31+
func dnsRawNameToDotted(rawI8 []int8) string {
32+
// Convert to byte slice up to first NUL
33+
b := make([]byte, 0, len(rawI8))
34+
for i := 0; i < len(rawI8); i++ {
35+
if rawI8[i] == 0 { // NUL terminator placed in kernel copy
36+
break
37+
}
38+
b = append(b, byte(rawI8[i]))
39+
}
40+
if len(b) == 0 {
41+
return ""
42+
}
43+
out := make([]byte, 0, len(b))
44+
i := 0
45+
first := true
46+
for i < len(b) {
47+
l := int(b[i])
48+
if l == 0 {
49+
break
50+
}
51+
// Stop on compression pointer (0xC0xx) since we didn't follow it in kernel
52+
if (l & 0xC0) == 0xC0 {
53+
break
54+
}
55+
i++
56+
if i+l > len(b) {
57+
break
58+
}
59+
if !first {
60+
out = append(out, '.')
61+
}
62+
first = false
63+
out = append(out, b[i:i+l]...)
64+
i += l
65+
}
66+
return string(out)
67+
}
68+
2969
func NewProtobuf() (*Protobuf, error) {
3070
log.Debugf("entering NewProtobuf")
3171
return &Protobuf{}, nil
@@ -120,6 +160,9 @@ func RecordToMap(fr *model.Record) config.GenericMap {
120160
out["DnsFlags"] = fr.Metrics.AdditionalMetrics.DnsRecord.Flags
121161
out["DnsFlagsResponseCode"] = DNSRcodeToStr(uint32(fr.Metrics.AdditionalMetrics.DnsRecord.Flags) & 0xF)
122162
out["DnsLatencyMs"] = fr.DNSLatency.Milliseconds()
163+
if name := dnsRawNameToDotted(fr.Metrics.AdditionalMetrics.DnsRecord.Name[:]); name != "" {
164+
out["DnsName"] = name
165+
}
123166
}
124167

125168
if fr.Metrics.AdditionalMetrics.PktDrops.LatestDropCause != 0 {

pkg/ebpf/bpf_arm64_bpfel.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ebpf/bpf_arm64_bpfel.o

4.16 KB
Binary file not shown.

pkg/ebpf/bpf_powerpc_bpfel.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ebpf/bpf_powerpc_bpfel.o

4.16 KB
Binary file not shown.

pkg/ebpf/bpf_s390_bpfeb.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)