Skip to content

Commit

Permalink
apermon: filter: is-frag support
Browse files Browse the repository at this point in the history
  • Loading branch information
magicnat committed May 8, 2023
1 parent 77d7388 commit ce6762e
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 8 deletions.
1 change: 1 addition & 0 deletions apermon.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ triggers {
# - source-port <number>; - match packets with the source port
# - destination-port <number>; - match packets with the destination port
# - protocol <tcp/udp/number>; - match packets with the protocol
# - is-fragment; - match packets that are fragments (i.e., frag-off != 0 or mf bit set)
filter {
# filters {} assumes and if and/or/not are not the root term. i.e.,
# here both in-interface and destination must match.
Expand Down
10 changes: 10 additions & 0 deletions condition.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ int cond_dst_port(const apermon_flow_record* record, const void* arg /* uint16_t
return (* (uint16_t *) arg) == record->dst_port;
}

int cond_is_fragment(const apermon_flow_record* record, const void* arg /* unused */) {
(void) arg;

if (record->flow_af == SFLOW_AF_INET6) {
return 0;
}

return record->frag_off != 0 || record->mf_bit;
}

void cond_begin(apermon_context *ctx) {
_ctx = ctx;
}
Expand Down
1 change: 1 addition & 0 deletions condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int cond_dst(const apermon_flow_record* record, const void* arg /* apermon_confi
int cond_proto(const apermon_flow_record* record, const void* arg /* uint8_t* */); /* keep only flow where l3proto in list */
int cond_src_port(const apermon_flow_record* record, const void* arg /* uint16_t* */); /* keep only flow where src port in list */
int cond_dst_port(const apermon_flow_record* record, const void* arg /* uint16_t* */); /* keep only flow where dst port in list */
int cond_is_fragment(const apermon_flow_record* record, const void* arg /* unused */); /* keep only fragment */

/* misc functions */

Expand Down
4 changes: 4 additions & 0 deletions config.l
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ destination-port {
return DESTINATION_PORT;
}

is-fragment {
return IS_FRAGMENT;
}

\{ {
return LBRACE;
}
Expand Down
5 changes: 4 additions & 1 deletion config.y
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
%token ACTIONS SCRIPT EVENTS BAN UNBAN ENV EQUALS
%token TRIGGERS NETWORKS DIRECTIONS INGRESS EGRESS AGGREGATE_TYPE HOST PREFIX NET
%token THRESHOLDS BPS PPS K M G
%token FILTER AND OR NOT SOURCE DESTINATION IN_INTERFACE OUT_INTERFACE PROTOCOL TCP UDP SOURCE_PORT DESTINATION_PORT
%token FILTER AND OR NOT SOURCE DESTINATION IN_INTERFACE OUT_INTERFACE PROTOCOL TCP UDP SOURCE_PORT DESTINATION_PORT IS_FRAGMENT

%token <u64> NUMBER
%token <d> DOUBLE
Expand Down Expand Up @@ -339,6 +339,9 @@ filter
*arg = $2;
$$ = new_cond_func_list_element(cond_dst_port, arg);
}
| IS_FRAGMENT SEMICOLON {
$$ = new_cond_func_list_element(cond_is_fragment, NULL);
}

action_list
: action
Expand Down
2 changes: 2 additions & 0 deletions extract.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ static inline int parse_inet(const uint8_t *buffer, size_t sz, apermon_flow_reco
apermon_flow_record *parsed = (apermon_flow_record *) malloc(sizeof(apermon_flow_record));

parsed->flow_af = SFLOW_AF_INET;
parsed->mf_bit = ntohs(hdr->frag_off) & 0x2000;
parsed->frag_off = ntohs(hdr->frag_off) & 0x1fff;
parsed->l3_proto = hdr->protocol;
parsed->dst_inet = hdr->daddr;
parsed->src_inet = hdr->saddr;
Expand Down
7 changes: 5 additions & 2 deletions extract.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ typedef struct _apermon_flow_records {
uint32_t out_ifindex;
uint32_t frame_length;

uint16_t frag_off;
uint16_t mf_bit;

union {
uint32_t src_inet;
uint8_t src_inet6[16];
Expand All @@ -26,8 +29,8 @@ typedef struct _apermon_flow_records {
};

uint8_t l3_proto;
uint16_t src_port; // valid iff l3proto = tcp or udp
uint16_t dst_port; // valid iff l3proto = tcp or udp
uint16_t src_port; // valid iff l3proto = tcp or udp && frag_off = 0
uint16_t dst_port; // valid iff l3proto = tcp or udp && frag_off = 0

struct _apermon_flow_records *next;
} apermon_flow_record;
Expand Down
6 changes: 4 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,11 @@ Notes:
- `src`: source IP / IPv6 address.
- `dst`: dst IP / IPv6 address.
- `proto`: IP protocol / IPv6 next header.
- `sport`: layer 4 src port.
- `dport`: layer 4 dst port.
- `sport`: layer 4 src port. (not valid if frag = 2)
- `dport`: layer 4 dst port. (not valid if frag = 2)
- `bytes`: number of bytes.
- `packets`: number of packets.
- `frag`: `0` - not fragmented, `1` - first fragment, `2` - non-first fragment
- For `unban` events, the following environment variables are passed to the script (values are just example):
- `TRIGGER=protect-my-network`: name of the trigger.
- `TYPE=unban`: type of event. Always `unban` for `unban` event.
Expand Down Expand Up @@ -274,6 +275,7 @@ Notes:
- `protocol <udp|tcp|number>;`: inet protocol number / inet6 next-header number.
- `source-port <number>;`: layer 4 source port.
- `destination-port <number>;`: layer 4 destination port.
- `is-fragment;`: IP fragments (i.e., `frag-off` != 0 or mf bit set)
- The three logical operators (`and`, `or`, and `not`) may be nested to build a more complex filter. If the root term under `filter {}` is not one of the logical operators, `and` is assumed.
- `actions` should be a list of names of actions defined in `actions`.

Expand Down
2 changes: 1 addition & 1 deletion scripts/summary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ TOP_FLOWS_COUNT="${TOP_FLOWS_COUNT:-10}"
printf 'out: %d Mbps, %d pps\n' "$((OUT_BPS / 1000000))" "$OUT_PPS"
printf '\n'

<<< "$FLOWS" sed 1d | sort -t, -k9 -nr | head -n $TOP_FLOWS_COUNT | grep -v '^$' | awk -F, '{ print "[" $4 "]:" $7 " -> [" $5 "]:" $8 "\n proto " $6 ", " $9 / 1000000 " mb, " $10 " pkts" }'
<<< "$FLOWS" sed 1d | sort -t, -k9 -nr | head -n $TOP_FLOWS_COUNT | grep -v '^$' | awk -F, '{ print "[" $4 "]:" $7 " -> [" $5 "]:" $8 "\n proto " $6 ", frag " $11 ", " $9 / 1000000 " mb, " $10 " pkts" }'
[ "`<<< "$FLOWS" sed 1d | wc -l`" -gt $TOP_FLOWS_COUNT ] && {
printf '(only top %d flow(s) are shown)\n' $TOP_FLOWS_COUNT
}
Expand Down
5 changes: 3 additions & 2 deletions trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,10 @@ static void run_trigger_script_ban(const apermon_config_triggers *config, const
inet_ntop(AF_INET6, fr->dst_inet6, addr2, sizeof(addr2));
}

offset += snprintf(strbuf + offset, sizeof(strbuf) - offset, "%u,%u,%u,%s,%s,%u,%u,%u,%u,%u\n",
offset += snprintf(strbuf + offset, sizeof(strbuf) - offset, "%u,%u,%u,%s,%s,%u,%u,%u,%u,%u,%u\n",
fr->flow_af, fr->in_ifindex, fr->out_ifindex, addr, addr2, fr->l3_proto,
fr->src_port, fr->dst_port, fr->frame_length * fr->rate, fr->rate
fr->src_port, fr->dst_port, fr->frame_length * fr->rate, fr->rate,
(fr->frag_off != 0) ? 2 : (fr->mf_bit ? 1 : 0)
);

if ((size_t) offset >= sizeof(strbuf)) {
Expand Down

0 comments on commit ce6762e

Please sign in to comment.