Skip to content

Commit 8cca560

Browse files
committed
WIP TLS
(wip status = pretty much done, except for handshake version (see code comment), maybe needs an experimental feature gate; correctness to be verified, as I'm getting less TLS flows than expected - am I missing something?) use tls.VersionName
1 parent 0549bb5 commit 8cca560

18 files changed

+143
-45
lines changed

bpf/flows.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ static __always_inline void update_existing_flow(flow_metrics *aggregate_flow, p
9393
aggregate_flow->flags |= pkt->flags;
9494
aggregate_flow->dscp = pkt->dscp;
9595
aggregate_flow->sampling = sampling;
96+
if (pkt->ssl_version != 0 && aggregate_flow->ssl_version != pkt->ssl_version) {
97+
if (aggregate_flow->ssl_version == 0) {
98+
aggregate_flow->ssl_version = pkt->ssl_version;
99+
} else {
100+
// If several SSL versions are found, keep just the smallest and set the "mismatch" flag
101+
if (pkt->ssl_version < aggregate_flow->ssl_version) {
102+
aggregate_flow->ssl_version = pkt->ssl_version;
103+
}
104+
aggregate_flow->misc_flags |= MISC_FLAGS_SSL_MISMATCH;
105+
}
106+
}
96107
} else if (if_index != 0) {
97108
// Only add info that we've seen this interface (we can also update end time & flags)
98109
aggregate_flow->end_mono_time_ts = pkt->current_ts;
@@ -197,6 +208,7 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
197208
new_flow.sampling = flow_sampling;
198209
__builtin_memcpy(new_flow.dst_mac, eth->h_dest, ETH_ALEN);
199210
__builtin_memcpy(new_flow.src_mac, eth->h_source, ETH_ALEN);
211+
new_flow.ssl_version = pkt.ssl_version;
200212

201213
long ret = bpf_map_update_elem(&aggregated_flows, &id, &new_flow, BPF_NOEXIST);
202214
if (ret != 0) {

bpf/types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ typedef __u64 u64;
7171

7272
#define MAX_PAYLOAD_SIZE 256
7373

74+
#define MISC_FLAGS_SSL_MISMATCH 0x01
75+
7476
// according to field 61 in https://www.iana.org/assignments/ipfix/ipfix.xhtml
7577
typedef enum direction_t {
7678
INGRESS,
@@ -110,6 +112,8 @@ typedef struct flow_metrics_t {
110112
u8 nb_observed_intf;
111113
u8 observed_direction[MAX_OBSERVED_INTERFACES];
112114
u32 observed_intf[MAX_OBSERVED_INTERFACES];
115+
u16 ssl_version;
116+
u8 misc_flags;
113117
} flow_metrics;
114118

115119
// Force emitting enums/structs into the ELF
@@ -192,6 +196,7 @@ typedef struct pkt_info_t {
192196
u16 dns_id;
193197
u16 dns_flags;
194198
u64 dns_latency;
199+
u16 ssl_version;
195200
} pkt_info;
196201

197202
// Structure for payload metadata

bpf/utils.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ static inline void set_flags(struct tcphdr *th, u16 *flags) {
5050
}
5151
}
5252

53+
// Extract TLS info
54+
static inline void fill_tls_info(struct tcphdr *tcp, void *data_end, pkt_info *pkt) {
55+
void *start_payload = ((void *)tcp) + (tcp->doff * 4);
56+
if (start_payload + 5 <= data_end) {
57+
if (((u8 *)start_payload)[0] == 0x16) {
58+
// TODO handshake special case, see https://www.netmeister.org/blog/tcpdump-ssl-and-tls.html
59+
pkt->ssl_version =
60+
((u16)(((u8 *)start_payload)[1])) << 8 | (u16)(((u8 *)start_payload)[2]);
61+
} else if (((u8 *)start_payload)[0] == 0x14 || ((u8 *)start_payload)[0] == 0x15 ||
62+
((u8 *)start_payload)[0] == 0x17) {
63+
pkt->ssl_version =
64+
((u16)(((u8 *)start_payload)[1])) << 8 | (u16)(((u8 *)start_payload)[2]);
65+
}
66+
}
67+
}
68+
5369
// Extract L4 info for the supported protocols
5470
static inline void fill_l4info(void *l4_hdr_start, void *data_end, u8 protocol, pkt_info *pkt) {
5571
flow_id *id = pkt->id;
@@ -62,6 +78,7 @@ static inline void fill_l4info(void *l4_hdr_start, void *data_end, u8 protocol,
6278
id->dst_port = bpf_ntohs(tcp->dest);
6379
set_flags(tcp, &pkt->flags);
6480
pkt->l4_hdr = (void *)tcp;
81+
fill_tls_info(tcp, data_end, pkt);
6582
}
6683
} break;
6784
case IPPROTO_UDP: {

pkg/decode/decode_protobuf.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ func RecordToMap(fr *model.Record) config.GenericMap {
148148
out["IPSecRetCode"] = int32(0)
149149
out["IPSecStatus"] = "success"
150150
}
151+
if tlsVersion := fr.Metrics.SSLVersionToString(); tlsVersion != "" {
152+
out["TLSVersion"] = tlsVersion
153+
}
154+
if fr.Metrics.HasSSLMismatch() {
155+
out["TLSMismatch"] = true
156+
}
151157
}
152158

153159
if fr.TimeFlowRtt != 0 {

pkg/decode/decode_protobuf_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func TestPBFlowToMap(t *testing.T) {
9898
},
9999
IpsecEncrypted: 1,
100100
IpsecEncryptedRet: 0,
101+
SslVersion: 0x0303,
101102
}
102103

103104
out := PBFlowToMap(flow)
@@ -155,5 +156,6 @@ func TestPBFlowToMap(t *testing.T) {
155156
"ZoneId": uint16(100),
156157
"IPSecRetCode": int32(0),
157158
"IPSecStatus": "success",
159+
"TLSVersion": "TLS 1.2",
158160
}, out)
159161
}

pkg/ebpf/bpf_arm64_bpfel.go

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ebpf/bpf_arm64_bpfel.o

1.97 KB
Binary file not shown.

pkg/ebpf/bpf_powerpc_bpfel.go

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ebpf/bpf_powerpc_bpfel.o

1.97 KB
Binary file not shown.

pkg/ebpf/bpf_s390_bpfeb.go

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)