Merge pull request #55 from simosund/pping-skip-syn

PPing: Add option to ignore SYN-packets
This commit is contained in:
Toke Høiland-Jørgensen
2022-11-06 14:18:10 +01:00
committed by GitHub
3 changed files with 39 additions and 24 deletions

View File

@@ -102,6 +102,7 @@ static const struct option long_options[] = {
{ "tcp", no_argument, NULL, 'T' }, // Calculate and report RTTs for TCP traffic (with TCP timestamps) { "tcp", no_argument, NULL, 'T' }, // Calculate and report RTTs for TCP traffic (with TCP timestamps)
{ "icmp", no_argument, NULL, 'C' }, // Calculate and report RTTs for ICMP echo-reply traffic { "icmp", no_argument, NULL, 'C' }, // Calculate and report RTTs for ICMP echo-reply traffic
{ "include-local", no_argument, NULL, 'l' }, // Also report "internal" RTTs { "include-local", no_argument, NULL, 'l' }, // Also report "internal" RTTs
{ "include-SYN", no_argument, NULL, 's' }, // Include SYN-packets in tracking (may fill up flow state with half-open connections)
{ 0, 0, NULL, 0 } { 0, 0, NULL, 0 }
}; };
@@ -170,8 +171,9 @@ static int parse_arguments(int argc, char *argv[], struct pping_config *config)
config->force = false; config->force = false;
config->bpf_config.track_tcp = false; config->bpf_config.track_tcp = false;
config->bpf_config.track_icmp = false; config->bpf_config.track_icmp = false;
config->bpf_config.skip_syn = true;
while ((opt = getopt_long(argc, argv, "hflTCi:r:R:t:c:F:I:", while ((opt = getopt_long(argc, argv, "hflTCsi:r:R:t:c:F:I:",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
@@ -266,6 +268,9 @@ static int parse_arguments(int argc, char *argv[], struct pping_config *config)
case 'C': case 'C':
config->bpf_config.track_icmp = true; config->bpf_config.track_icmp = true;
break; break;
case 's':
config->bpf_config.skip_syn = false;
break;
case 'h': case 'h':
printf("HELP:\n"); printf("HELP:\n");
print_usage(argv); print_usage(argv);

View File

@@ -64,7 +64,8 @@ struct bpf_config {
bool track_tcp; bool track_tcp;
bool track_icmp; bool track_icmp;
bool localfilt; bool localfilt;
__u32 reserved; bool skip_syn;
__u8 reserved[3];
}; };
/* /*
@@ -105,7 +106,8 @@ struct flow_state {
__u32 outstanding_timestamps; __u32 outstanding_timestamps;
enum connection_state conn_state; enum connection_state conn_state;
enum flow_event_reason opening_reason; enum flow_event_reason opening_reason;
__u8 reserved[6]; bool has_been_timestamped;
__u8 reserved[5];
}; };
/* /*

View File

@@ -104,6 +104,7 @@ struct packet_info {
bool reply_pid_valid; // reply_identifier can be used to match packet bool reply_pid_valid; // reply_identifier can be used to match packet
enum flow_event_type event_type; // flow event triggered by packet enum flow_event_type event_type; // flow event triggered by packet
enum flow_event_reason event_reason; // reason for triggering flow event enum flow_event_reason event_reason; // reason for triggering flow event
bool wait_first_edge; // Do we need to wait for the first identifier change before timestamping?
}; };
/* /*
@@ -116,6 +117,7 @@ struct protocol_info {
bool reply_pid_valid; bool reply_pid_valid;
enum flow_event_type event_type; enum flow_event_type event_type;
enum flow_event_reason event_reason; enum flow_event_reason event_reason;
bool wait_first_edge;
}; };
char _license[] SEC("license") = "GPL"; char _license[] SEC("license") = "GPL";
@@ -339,6 +341,9 @@ static int parse_tcp_identifier(struct parsing_context *pctx,
if (parse_tcphdr(&pctx->nh, pctx->data_end, &hdr) < 0) if (parse_tcphdr(&pctx->nh, pctx->data_end, &hdr) < 0)
return -1; return -1;
if (config.skip_syn && hdr->syn)
return -1;
if (parse_tcp_ts(hdr, pctx->data_end, &proto_info->pid, if (parse_tcp_ts(hdr, pctx->data_end, &proto_info->pid,
&proto_info->reply_pid) < 0) &proto_info->reply_pid) < 0)
return -1; //Possible TODO, fall back on seq/ack instead return -1; //Possible TODO, fall back on seq/ack instead
@@ -361,9 +366,11 @@ static int parse_tcp_identifier(struct parsing_context *pctx,
proto_info->event_type = FLOW_EVENT_OPENING; proto_info->event_type = FLOW_EVENT_OPENING;
proto_info->event_reason = proto_info->event_reason =
hdr->ack ? EVENT_REASON_SYN_ACK : EVENT_REASON_SYN; hdr->ack ? EVENT_REASON_SYN_ACK : EVENT_REASON_SYN;
proto_info->wait_first_edge = false;
} else { } else {
proto_info->event_type = FLOW_EVENT_NONE; proto_info->event_type = FLOW_EVENT_NONE;
proto_info->event_reason = EVENT_REASON_NONE; proto_info->event_reason = EVENT_REASON_NONE;
proto_info->wait_first_edge = true;
} }
*sport = hdr->source; *sport = hdr->source;
@@ -416,6 +423,7 @@ static int parse_icmp6_identifier(struct parsing_context *pctx,
proto_info->event_type = FLOW_EVENT_NONE; proto_info->event_type = FLOW_EVENT_NONE;
proto_info->event_reason = EVENT_REASON_NONE; proto_info->event_reason = EVENT_REASON_NONE;
proto_info->wait_first_edge = false;
*sport = hdr->icmp6_identifier; *sport = hdr->icmp6_identifier;
*dport = hdr->icmp6_identifier; *dport = hdr->icmp6_identifier;
*icmp6h = hdr; *icmp6h = hdr;
@@ -453,6 +461,7 @@ static int parse_icmp_identifier(struct parsing_context *pctx,
proto_info->event_type = FLOW_EVENT_NONE; proto_info->event_type = FLOW_EVENT_NONE;
proto_info->event_reason = EVENT_REASON_NONE; proto_info->event_reason = EVENT_REASON_NONE;
proto_info->wait_first_edge = false;
*sport = hdr->un.echo.id; *sport = hdr->un.echo.id;
*dport = hdr->un.echo.id; *dport = hdr->un.echo.id;
*icmph = hdr; *icmph = hdr;
@@ -531,6 +540,7 @@ static int parse_packet_identifier(struct parsing_context *pctx,
p_info->reply_pid_valid = proto_info.reply_pid_valid; p_info->reply_pid_valid = proto_info.reply_pid_valid;
p_info->event_type = proto_info.event_type; p_info->event_type = proto_info.event_type;
p_info->event_reason = proto_info.event_reason; p_info->event_reason = proto_info.event_reason;
p_info->wait_first_edge = proto_info.wait_first_edge;
if (p_info->pid.flow.ipv == AF_INET) { if (p_info->pid.flow.ipv == AF_INET) {
map_ipv4_to_ipv6(&p_info->pid.flow.saddr.ip, map_ipv4_to_ipv6(&p_info->pid.flow.saddr.ip,
@@ -705,14 +715,19 @@ static void init_flowstate(struct flow_state *f_state,
{ {
f_state->conn_state = CONNECTION_STATE_WAITOPEN; f_state->conn_state = CONNECTION_STATE_WAITOPEN;
f_state->last_timestamp = p_info->time; f_state->last_timestamp = p_info->time;
/* We should only ever create new flows for packet with valid pid,
so assume pid is valid*/
f_state->last_id = p_info->pid.identifier;
f_state->opening_reason = p_info->event_type == FLOW_EVENT_OPENING ? f_state->opening_reason = p_info->event_type == FLOW_EVENT_OPENING ?
p_info->event_reason : p_info->event_reason :
EVENT_REASON_FIRST_OBS_PCKT; EVENT_REASON_FIRST_OBS_PCKT;
f_state->has_been_timestamped = false;
} }
static void init_empty_flowstate(struct flow_state *f_state) static void init_empty_flowstate(struct flow_state *f_state)
{ {
f_state->conn_state = CONNECTION_STATE_EMPTY; f_state->conn_state = CONNECTION_STATE_EMPTY;
f_state->has_been_timestamped = false;
} }
/* /*
@@ -732,18 +747,15 @@ static void init_dualflow_state(struct dual_flow_state *df_state,
} }
static struct dual_flow_state * static struct dual_flow_state *
create_dualflow_state(void *ctx, struct packet_info *p_info, bool *new_flow) create_dualflow_state(void *ctx, struct packet_info *p_info)
{ {
struct network_tuple *key = get_dualflow_key_from_packet(p_info); struct network_tuple *key = get_dualflow_key_from_packet(p_info);
struct dual_flow_state new_state = { 0 }; struct dual_flow_state new_state = { 0 };
init_dualflow_state(&new_state, p_info); init_dualflow_state(&new_state, p_info);
if (bpf_map_update_elem(&flow_state, key, &new_state, BPF_NOEXIST) == if (bpf_map_update_elem(&flow_state, key, &new_state, BPF_NOEXIST) !=
0) { 0) {
if (new_flow)
*new_flow = true;
} else {
send_map_full_event(ctx, p_info, PPING_MAP_FLOWSTATE); send_map_full_event(ctx, p_info, PPING_MAP_FLOWSTATE);
return NULL; return NULL;
} }
@@ -752,8 +764,7 @@ create_dualflow_state(void *ctx, struct packet_info *p_info, bool *new_flow)
} }
static struct dual_flow_state * static struct dual_flow_state *
lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info, lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info)
bool *new_flow)
{ {
struct dual_flow_state *df_state; struct dual_flow_state *df_state;
@@ -768,7 +779,7 @@ lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info,
p_info->event_type == FLOW_EVENT_CLOSING_BOTH) p_info->event_type == FLOW_EVENT_CLOSING_BOTH)
return NULL; return NULL;
return create_dualflow_state(ctx, p_info, new_flow); return create_dualflow_state(ctx, p_info);
} }
static bool is_flowstate_active(struct flow_state *f_state) static bool is_flowstate_active(struct flow_state *f_state)
@@ -778,15 +789,11 @@ static bool is_flowstate_active(struct flow_state *f_state)
} }
static void update_forward_flowstate(struct packet_info *p_info, static void update_forward_flowstate(struct packet_info *p_info,
struct flow_state *f_state, bool *new_flow) struct flow_state *f_state)
{ {
// "Create" flowstate if it's empty // "Create" flowstate if it's empty
if (f_state->conn_state == CONNECTION_STATE_EMPTY && if (f_state->conn_state == CONNECTION_STATE_EMPTY && p_info->pid_valid)
p_info->pid_valid) {
init_flowstate(f_state, p_info); init_flowstate(f_state, p_info);
if (new_flow)
*new_flow = true;
}
if (is_flowstate_active(f_state)) { if (is_flowstate_active(f_state)) {
f_state->sent_pkts++; f_state->sent_pkts++;
@@ -902,7 +909,7 @@ static bool is_new_identifier(struct packet_id *pid, struct flow_state *f_state)
* Attempt to create a timestamp-entry for packet p_info for flow in f_state * Attempt to create a timestamp-entry for packet p_info for flow in f_state
*/ */
static void pping_timestamp_packet(struct flow_state *f_state, void *ctx, static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
struct packet_info *p_info, bool new_flow) struct packet_info *p_info)
{ {
if (!is_flowstate_active(f_state) || !p_info->pid_valid) if (!is_flowstate_active(f_state) || !p_info->pid_valid)
return; return;
@@ -912,12 +919,13 @@ static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
return; return;
// Check if identfier is new // Check if identfier is new
if (!new_flow && !is_new_identifier(&p_info->pid, f_state)) if ((f_state->has_been_timestamped || p_info->wait_first_edge) &&
!is_new_identifier(&p_info->pid, f_state))
return; return;
f_state->last_id = p_info->pid.identifier; f_state->last_id = p_info->pid.identifier;
// Check rate-limit // Check rate-limit
if (!new_flow && if (f_state->has_been_timestamped &&
is_rate_limited(p_info->time, f_state->last_timestamp, is_rate_limited(p_info->time, f_state->last_timestamp,
config.use_srtt ? f_state->srtt : f_state->min_rtt)) config.use_srtt ? f_state->srtt : f_state->min_rtt))
return; return;
@@ -928,6 +936,7 @@ static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
* the next available map slot somewhat fairer between heavy and sparse * the next available map slot somewhat fairer between heavy and sparse
* flows. * flows.
*/ */
f_state->has_been_timestamped = true;
f_state->last_timestamp = p_info->time; f_state->last_timestamp = p_info->time;
if (bpf_map_update_elem(&packet_ts, &p_info->pid, &p_info->time, if (bpf_map_update_elem(&packet_ts, &p_info->pid, &p_info->time,
@@ -993,15 +1002,14 @@ static void pping_parsed_packet(void *ctx, struct packet_info *p_info)
{ {
struct dual_flow_state *df_state; struct dual_flow_state *df_state;
struct flow_state *fw_flow, *rev_flow; struct flow_state *fw_flow, *rev_flow;
bool new_flow = false;
df_state = lookup_or_create_dualflow_state(ctx, p_info, &new_flow); df_state = lookup_or_create_dualflow_state(ctx, p_info);
if (!df_state) if (!df_state)
return; return;
fw_flow = get_flowstate_from_packet(df_state, p_info); fw_flow = get_flowstate_from_packet(df_state, p_info);
update_forward_flowstate(p_info, fw_flow, &new_flow); update_forward_flowstate(p_info, fw_flow);
pping_timestamp_packet(fw_flow, ctx, p_info, new_flow); pping_timestamp_packet(fw_flow, ctx, p_info);
rev_flow = get_reverse_flowstate_from_packet(df_state, p_info); rev_flow = get_reverse_flowstate_from_packet(df_state, p_info);
update_reverse_flowstate(ctx, p_info, rev_flow); update_reverse_flowstate(ctx, p_info, rev_flow);