mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Add feature to drop or accept specific packet transmit over edge network interface by rules. (#489)
* Add new file 'network_traffic_filter.c/.h" * Add feature to drop or accept specific packet transmit over edge network interface by rules. * fix CMakeLists.txt typo * Update Rule String Format * replace -F (filter) with -R (rule) for traffic restrictions. * Update edge help (-h) message. Update documents.
This commit is contained in:
parent
e65fd984d7
commit
a840aebb83
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -25,3 +25,5 @@ packages/etc/systemd/system/edge.service
|
|||
packages/etc/systemd/system/edge@.service
|
||||
packages/etc/systemd/system/supernode.service
|
||||
*dSYM*
|
||||
|
||||
cmake-build-*/
|
||||
|
|
|
@ -115,7 +115,7 @@ add_library(n2n STATIC
|
|||
src/tuntap_linux.c
|
||||
src/tuntap_osx.c
|
||||
src/n2n_regex.c
|
||||
)
|
||||
src/network_traffic_filter.c)
|
||||
|
||||
if(DEFINED WIN32)
|
||||
add_library(edge_utils_win32 src/edge_utils_win32.c)
|
||||
|
|
|
@ -97,6 +97,10 @@ The [TAP Configuration Guide](https://github.com/ntop/n2n/blob/dev/doc/TapConfig
|
|||
|
||||
Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. n2n supports routing needs providing options for packet forwarding (`-r`) including broadcasts (`-E`) as well as temporarily modifying the routing table (`-n`). Details can be found in the [Routing document](doc/Routing.md).
|
||||
|
||||
## Traffic Restrictions
|
||||
|
||||
It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times. Details can be found in the [Traffic Restrictions](doc/TrafficRestrictions.md).
|
||||
|
||||
## Contribution
|
||||
|
||||
You can contribute to n2n in various ways:
|
||||
|
|
41
doc/TrafficRestrictions.md
Normal file
41
doc/TrafficRestrictions.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Traffic Restrictions
|
||||
|
||||
It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times.
|
||||
|
||||
## Rule String Format
|
||||
|
||||
rule_str format: `src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-`
|
||||
|
||||
`ip/len` indicate a cidr block, len can be ignore, means single ip (not cidr block) will be use in filter rule.
|
||||
|
||||
`+`,`-` after `TCP`,`UDP`,`ICMP` proto type indicate allow or drop packet of that proto. if any of above three proto missed, the rule will not take effect for that proto.
|
||||
|
||||
Ports range `[s_port,e_port]` can be instead by single port number. If not specify, `[0,65535]` will be used. Ports range include start_port and end_port.
|
||||
|
||||
examples:
|
||||
`192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+`
|
||||
`192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+`
|
||||
`192.168.1.5,192.168.0.7,TCP-,UDP-,ICMP-` // packets by all proto of all ports from 192.158.1.5 to any ports of 192.168.0.7 will be dropped.
|
||||
|
||||
## Multiple Rules
|
||||
|
||||
`-R rule_str` can be used multiple times to add multiple rules. Each `-R rule_str` add one rule. for example:
|
||||
|
||||
`edge -c xxxx -k xxxx -a 192.168.100.5 -l xxx.xxx.xxx.xxx:1234 -r -R 192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+ -R 192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+ -R 192.168.1.5,192.168.0.7,TCP-`
|
||||
|
||||
## Matching Rules Priority
|
||||
|
||||
If multiple rules matching packet's ips and ports, the rule with smaller cidr block(smaller address space) will be selected. That means rules with larger `len` value has higher priority.
|
||||
|
||||
Actually, current implementation will add the `len` of src cidr and dst cidr of each matched rules as priority value, the rule with largest priority value will take effect.
|
||||
|
||||
## Blocklist/Allowlist mode
|
||||
|
||||
Packets that cannot match any rule will be accepted by default. Users can add rules to block traffics.
|
||||
|
||||
This behavior can be change by add the rule : `0.0.0.0/0:[0,65535],0.0.0.0/0:[0,65535],TCP-,UDP-,ICMP-`. Then all traffic will be dropped, users need add rules to allow traffics.
|
||||
|
||||
for example, `-R 0.0.0.0/0,0.0.0.0/0,TCP-,UDP-,ICMP- -R 192.168.100.0/24,192.168.100.0/24,ICMP+` dropped all traffic, except ICMP traffics inside `192.168.100.0/24`.
|
||||
|
||||
More complex behavior can be set with the feature of `Matching Rules Priority`.
|
||||
|
25
edge.8
25
edge.8
|
@ -131,6 +131,31 @@ traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
|
|||
|
||||
But this method does not always work due to various local network device policy.
|
||||
.TP
|
||||
\-R <rule_str>
|
||||
Add rule to drop or accept specific packet transmit over edge network interface.
|
||||
-R rule_str can be used multiple times to add multiple rules. Each -R rule_str add
|
||||
one rule.
|
||||
|
||||
rule_str format:"src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-".
|
||||
|
||||
ip/len indicate a cidr block, len can be ignore, means single ip(not cidr block)
|
||||
will be use in filter rule.
|
||||
|
||||
+,- after TCP,UDP,ICMP proto type indicate allow or drop packet of that proto.
|
||||
if any of above three proto missed, the rule will not take effect for that proto.
|
||||
|
||||
Ports range [s_port,e_port] can be instead by single port number. If not specify, [0,65535]
|
||||
will be used. Ports range include start_port and end_port. If multiple rules matching packet's
|
||||
ips and ports, the rule with smaller cidr block(smaller address space) will be selected. That
|
||||
means rules with larger len value has higher priority.
|
||||
|
||||
Packets that cannot match any rule will be accepted by default. Users can add rules to
|
||||
block traffics. This behavior can be change by add the rule : `0.0.0.0/0:[0,65535],0.0.0.0/0:
|
||||
[0,65535],TCP-,UDP-,ICMP-`. Then all traffic will be dropped, users need add rules to allow
|
||||
traffics.
|
||||
|
||||
for example : `-R 0.0.0.0/0,0.0.0.0/0,TCP-,UDP-,ICMP- -R 192.168.100.0/24,192.168.100.0/24,ICMP+`,
|
||||
|
||||
\-v
|
||||
more verbose logging (may be specified several times for more verbosity).
|
||||
.SH ENVIRONMENT
|
||||
|
|
|
@ -254,6 +254,72 @@ typedef struct n2n_edge_callbacks {
|
|||
} n2n_edge_callbacks_t;
|
||||
|
||||
/* ***************************************************** */
|
||||
// network traffic filter
|
||||
|
||||
typedef struct port_range{
|
||||
uint16_t start_port; // range contain 'start_port' self
|
||||
uint16_t end_port; // range contain 'end_port' self
|
||||
} port_range_t;
|
||||
|
||||
typedef struct filter_rule_key
|
||||
{
|
||||
in_addr_t src_net_cidr;
|
||||
uint8_t src_net_bit_len;
|
||||
port_range_t src_port_range;
|
||||
in_addr_t dst_net_cidr;
|
||||
uint8_t dst_net_bit_len;
|
||||
port_range_t dst_port_range;
|
||||
uint8_t bool_tcp_configured;
|
||||
uint8_t bool_udp_configured;
|
||||
uint8_t bool_icmp_configured;
|
||||
} filter_rule_key_t;
|
||||
|
||||
typedef struct filter_rule
|
||||
{
|
||||
filter_rule_key_t key;
|
||||
|
||||
uint8_t bool_accept_icmp;
|
||||
uint8_t bool_accept_udp;
|
||||
uint8_t bool_accept_tcp;
|
||||
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} filter_rule_t;
|
||||
|
||||
|
||||
//rule_str format: src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-
|
||||
//
|
||||
//ip/len indicate a cidr block, len can be ignore, means single ip (not cidr block) will be use in filter rule.
|
||||
//
|
||||
//'+','-' after proto type indicate allow or disallow that proto transmit packet. if any of above three proto missed, it will be disallow.
|
||||
//
|
||||
//[s_port,e_port] can be instead by single port number, if not specify, 0-65535 ports will be used. ports range include start_port and end_port.
|
||||
//
|
||||
//examples:
|
||||
//192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+
|
||||
//192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+
|
||||
//192.168.1.5,192.168.0.7 // packets by all proto of all ports from 192.158.1.5 to any ports of 192.168.0.7 will be disallow(dropped).
|
||||
//
|
||||
// for impl, see: network_traffic_filter.c
|
||||
uint8_t process_traffic_filter_rule_str(const char* rule_str, filter_rule_t* rule_struct);
|
||||
|
||||
/*
|
||||
* network traffic filter interface
|
||||
*/
|
||||
typedef struct network_traffic_filter
|
||||
{
|
||||
/* A packet has been received from a peer. N2N_DROP can be returned to
|
||||
* drop the packet. The packet payload can be modified. This only allows
|
||||
* the packet size to be reduced */
|
||||
n2n_verdict (*filter_packet_from_peer)(struct network_traffic_filter* filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size);
|
||||
|
||||
/* A packet has been received from the TAP interface. N2N_DROP can be
|
||||
* returned to drop the packet. The packet payload can be modified.
|
||||
* This only allows the packet size to be reduced */
|
||||
n2n_verdict (*filter_packet_from_tap)(struct network_traffic_filter* filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size);
|
||||
|
||||
} network_traffic_filter_t;
|
||||
|
||||
/* *************************************************** */
|
||||
|
||||
typedef struct n2n_tuntap_priv_config {
|
||||
char tuntap_dev_name[N2N_IFNAMSIZ];
|
||||
|
@ -295,6 +361,7 @@ typedef struct n2n_edge_conf {
|
|||
int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */
|
||||
int local_port;
|
||||
int mgmt_port;
|
||||
filter_rule_t *network_traffic_filter_rules;
|
||||
} n2n_edge_conf_t;
|
||||
|
||||
|
||||
|
@ -347,6 +414,8 @@ struct n2n_edge {
|
|||
struct n2n_edge_stats stats; /**< Statistics */
|
||||
|
||||
n2n_tuntap_priv_config_t tuntap_priv_conf; /**< Tuntap config */
|
||||
|
||||
network_traffic_filter_t *network_traffic_filter;
|
||||
};
|
||||
|
||||
|
||||
|
|
45
include/network_traffic_filter.h
Normal file
45
include/network_traffic_filter.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* (C) 2007-20 - ntop.org and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not see see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Zhou Bin <joshuafc@foxmail.com>
|
||||
//
|
||||
|
||||
#ifndef N2N_NETWORK_TRAFFIC_FILTER_H
|
||||
#define N2N_NETWORK_TRAFFIC_FILTER_H
|
||||
|
||||
#include "n2n.h"
|
||||
|
||||
/*
|
||||
* add feature to drop or accept specific packet transmit over edge network interface by rules.
|
||||
*
|
||||
* below structs and function used 'n2n_verdict' and other structs, so defined in 'n2n.h', to avoid header files circular dependency.
|
||||
* port_range_t, filter_rule_key_t, filter_rule_t, network_traffic_filter_t
|
||||
* uint8_t process_traffic_filter_rule_str(const char* rule_str, filter_rule_t* rule_struct);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
network_traffic_filter_t* create_network_traffic_filter();
|
||||
|
||||
void destroy_network_traffic_filter(network_traffic_filter_t* filter);
|
||||
|
||||
void network_traffic_filter_add_rule(network_traffic_filter_t* filter, filter_rule_t* rules);
|
||||
|
||||
|
||||
#endif //N2N_NETWORK_TRAFFIC_FILTER_H
|
22
src/edge.c
22
src/edge.c
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <sys/capability.h>
|
||||
#include <sys/prctl.h>
|
||||
#include "network_traffic_filter.h"
|
||||
|
||||
static cap_value_t cap_values[] = {
|
||||
//CAP_NET_RAW, /* Use RAW and PACKET sockets */
|
||||
|
@ -143,7 +144,7 @@ static void help() {
|
|||
#ifndef __APPLE__
|
||||
"[-D] "
|
||||
#endif
|
||||
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-H] [-z[<compression algo>]] [-h]\n\n");
|
||||
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-H] [-z[<compression algo>]] [-R <rule_str>] [-h]\n\n");
|
||||
|
||||
#if defined(N2N_CAN_NAME_IFACE)
|
||||
printf("-d <tap device> | tap device name\n");
|
||||
|
@ -190,6 +191,8 @@ static void help() {
|
|||
#endif
|
||||
printf("-n <cidr:gateway> | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n");
|
||||
printf("-v | Make more verbose. Repeat as required.\n");
|
||||
printf("-R <rule_str> | Drop or accept packets by rules. Can be set multiple times. \n");
|
||||
printf(" | Rule format: src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/- \n");
|
||||
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
|
||||
|
||||
printf("\nEnvironment variables:\n");
|
||||
|
@ -516,6 +519,21 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec
|
|||
setTraceLevel(getTraceLevel() + 1);
|
||||
break;
|
||||
|
||||
case 'R': /* network traffic filter */
|
||||
{
|
||||
filter_rule_t *new_rule = malloc(sizeof(filter_rule_t));
|
||||
memset(new_rule, 0, sizeof(filter_rule_t));
|
||||
if(process_traffic_filter_rule_str(optargument, new_rule) )
|
||||
{
|
||||
HASH_ADD(hh, conf->network_traffic_filter_rules, key, sizeof(filter_rule_key_t), new_rule);
|
||||
}else{
|
||||
free(new_rule);
|
||||
traceEvent(TRACE_WARNING, "Invalid filter rule: %s", optargument);
|
||||
return(-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored", (char)optkey);
|
||||
|
@ -547,7 +565,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tuntap
|
|||
u_char c;
|
||||
|
||||
while ((c = getopt_long(argc, argv,
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:SDL:z::A::Hn:"
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:SDL:z::A::Hn:R:"
|
||||
#ifdef __linux__
|
||||
"T:"
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "network_traffic_filter.h"
|
||||
#include "n2n.h"
|
||||
#include "edge_utils_win32.h"
|
||||
|
||||
|
@ -270,6 +271,9 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
|
|||
goto edge_init_error;
|
||||
}
|
||||
|
||||
eee->network_traffic_filter = create_network_traffic_filter();
|
||||
network_traffic_filter_add_rule(eee->network_traffic_filter, eee->conf.network_traffic_filter_rules);
|
||||
|
||||
//edge_init_success:
|
||||
*rv = 0;
|
||||
return(eee);
|
||||
|
@ -1173,11 +1177,16 @@ static int handle_PACKET(n2n_edge_t * eee,
|
|||
}
|
||||
}
|
||||
|
||||
if( eee->network_traffic_filter->filter_packet_from_peer( eee->network_traffic_filter, eee, orig_sender,
|
||||
eth_payload, eth_size ) == N2N_DROP){
|
||||
traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)eth_size);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(eee->cb.packet_from_peer) {
|
||||
uint16_t tmp_eth_size = eth_size;
|
||||
if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, &tmp_eth_size) == N2N_DROP) {
|
||||
traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size);
|
||||
|
||||
return(0);
|
||||
}
|
||||
eth_size = tmp_eth_size;
|
||||
|
@ -1724,6 +1733,11 @@ void edge_read_from_tap(n2n_edge_t * eee) {
|
|||
}
|
||||
else
|
||||
{
|
||||
if( eee->network_traffic_filter->filter_packet_from_tap( eee->network_traffic_filter, eee, eth_pkt,
|
||||
len) == N2N_DROP){
|
||||
traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)len);
|
||||
return;
|
||||
}
|
||||
if(eee->cb.packet_from_tap) {
|
||||
uint16_t tmp_len = len;
|
||||
if(eee->cb.packet_from_tap(eee, eth_pkt, &tmp_len) == N2N_DROP) {
|
||||
|
@ -2295,6 +2309,8 @@ void edge_term(n2n_edge_t * eee) {
|
|||
|
||||
edge_cleanup_routes(eee);
|
||||
|
||||
destroy_network_traffic_filter(eee->network_traffic_filter);
|
||||
|
||||
closeTraceFile();
|
||||
|
||||
free(eee);
|
||||
|
@ -2793,6 +2809,17 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
|||
void edge_term_conf(n2n_edge_conf_t *conf) {
|
||||
if (conf->routes) free(conf->routes);
|
||||
if (conf->encrypt_key) free(conf->encrypt_key);
|
||||
|
||||
if(conf->network_traffic_filter_rules)
|
||||
{
|
||||
filter_rule_t *el = 0, *tmp = 0;
|
||||
HASH_ITER(hh, conf->network_traffic_filter_rules, el, tmp)
|
||||
{
|
||||
HASH_DEL(conf->network_traffic_filter_rules, el);
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
|
743
src/network_traffic_filter.c
Normal file
743
src/network_traffic_filter.c
Normal file
|
@ -0,0 +1,743 @@
|
|||
/**
|
||||
* (C) 2007-20 - ntop.org and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not see see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "network_traffic_filter.h"
|
||||
#include "uthash.h"
|
||||
|
||||
#include "netinet/tcp.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
// cache that hit less than 10 while 10000 package processed will be delete;
|
||||
#define CLEAR_CACHE_EVERY_X_COUNT 10000
|
||||
#define CLAER_CACHE_ACTIVE_COUNT 10
|
||||
|
||||
typedef enum {
|
||||
FPP_UNKNOWN=0,
|
||||
FPP_ARP = 1,
|
||||
FPP_TCP=2,
|
||||
FPP_UDP=3,
|
||||
FPP_ICMP=4,
|
||||
FPP_IGMP=5
|
||||
} filter_packet_proto;
|
||||
|
||||
const char* get_filter_packet_proto_name(filter_packet_proto proto)
|
||||
{
|
||||
switch (proto)
|
||||
{
|
||||
case FPP_ARP:
|
||||
return "ARP";
|
||||
case FPP_TCP:
|
||||
return "TCP";
|
||||
case FPP_UDP:
|
||||
return "UDP";
|
||||
case FPP_ICMP:
|
||||
return "ICMP";
|
||||
case FPP_IGMP:
|
||||
return "IGMP";
|
||||
default:
|
||||
return "UNKNOWN_PROTO";
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct packet_address_proto_info{
|
||||
in_addr_t src_ip;
|
||||
uint16_t src_port;
|
||||
in_addr_t dst_ip;
|
||||
uint16_t dst_port;
|
||||
filter_packet_proto proto;
|
||||
}packet_address_proto_info_t;
|
||||
|
||||
const char* get_filter_packet_info_log_string(packet_address_proto_info_t* info)
|
||||
{
|
||||
static char buf[1024] = {0};
|
||||
switch (info->proto)
|
||||
{
|
||||
case FPP_ARP:
|
||||
case FPP_ICMP:
|
||||
case FPP_IGMP:
|
||||
return get_filter_packet_proto_name(info->proto);
|
||||
case FPP_TCP:
|
||||
case FPP_UDP:
|
||||
{
|
||||
struct in_addr src, dst;
|
||||
src.s_addr = info->src_ip;
|
||||
dst.s_addr = info->dst_ip;
|
||||
const char* proto = get_filter_packet_proto_name(info->proto);
|
||||
char src_ip[64] = {0}; char dst_ip[64] = {0};
|
||||
strcpy( src_ip, inet_ntoa(src)); strcpy(dst_ip, inet_ntoa(dst));
|
||||
sprintf(buf, "%s\t%s:%d->%s:%d", proto, src_ip, info->src_port, dst_ip, info->dst_port);
|
||||
return buf;
|
||||
}
|
||||
default:
|
||||
return "UNKNOWN_PROTO";
|
||||
}
|
||||
}
|
||||
|
||||
void collect_packet_info(packet_address_proto_info_t* out_info, unsigned char *buffer, int size) {
|
||||
struct ethhdr *hdr_ether = (struct ethhdr*)buffer;
|
||||
memset(out_info, 0, sizeof(packet_address_proto_info_t));
|
||||
uint16_t ether_type = ntohs(hdr_ether->h_proto);
|
||||
switch (ether_type) {
|
||||
case 0x0800:
|
||||
{
|
||||
buffer += ETH_HLEN; size -= ETH_HLEN; if(size <= 0) return;
|
||||
struct iphdr *hdr_ip = (struct iphdr*)buffer;
|
||||
switch (hdr_ip->version)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
out_info->src_ip = hdr_ip->saddr;
|
||||
out_info->dst_ip = hdr_ip->daddr;
|
||||
switch (hdr_ip->protocol) {
|
||||
case 0x01:
|
||||
out_info->proto = FPP_ICMP;
|
||||
break;
|
||||
case 0x02:
|
||||
out_info->proto = FPP_IGMP;
|
||||
break;
|
||||
case 0x06:
|
||||
{
|
||||
out_info->proto = FPP_TCP;
|
||||
buffer += hdr_ip->ihl * 4; size -= hdr_ip->ihl * 4; if(size <= 0) return;
|
||||
struct tcphdr *hdr_tcp = (struct tcphdr*)buffer;
|
||||
out_info->src_port = ntohs(hdr_tcp->th_sport);
|
||||
out_info->dst_port = ntohs(hdr_tcp->th_dport);
|
||||
break;
|
||||
}
|
||||
case 0x11:
|
||||
{
|
||||
out_info->proto = FPP_UDP;
|
||||
buffer += hdr_ip->ihl * 4; size -= hdr_ip->ihl * 4; if(size <= 0) return;
|
||||
struct udphdr *udp_hdr = (struct tcphdr*)buffer;
|
||||
out_info->src_port = ntohs(udp_hdr->uh_sport);
|
||||
out_info->dst_port = ntohs(udp_hdr->uh_dport);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out_info->proto = FPP_UNKNOWN;
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
// TODO: IPV6 Not Support
|
||||
out_info->proto = FPP_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out_info->proto = FPP_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0806:
|
||||
out_info->proto = FPP_ARP;
|
||||
break;
|
||||
case 0x86DD:
|
||||
out_info->proto = FPP_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
printf("EtherType 0x%04X", ether_type);
|
||||
};
|
||||
}
|
||||
|
||||
const char* get_filter_rule_info_log_string(filter_rule_t* rule)
|
||||
{
|
||||
static char buf[1024] = {0};
|
||||
char* print_start = buf;
|
||||
char src_net[64] = {0}; char dst_net[64] = {0};
|
||||
struct in_addr src, dst;
|
||||
src.s_addr = rule->key.src_net_cidr;
|
||||
dst.s_addr = rule->key.dst_net_cidr;
|
||||
strcpy(src_net, inet_ntoa(src)); strcpy(dst_net, inet_ntoa(dst));
|
||||
print_start += sprintf(print_start, "%s/%d:[%d,%d],%s/%d:[%d,%d]",
|
||||
src_net, rule->key.src_net_bit_len, rule->key.src_port_range.start_port, rule->key.src_port_range.end_port,
|
||||
dst_net, rule->key.dst_net_bit_len, rule->key.dst_port_range.start_port, rule->key.dst_port_range.end_port,
|
||||
rule->bool_accept_tcp ? '+' : '-', rule->bool_accept_udp ? '+' : '-', rule->bool_accept_icmp ? '+' : '-');
|
||||
if(rule->key.bool_tcp_configured)
|
||||
print_start += sprintf(print_start, ",TCP%c", rule->bool_accept_tcp ? '+' : '-');
|
||||
if(rule->key.bool_udp_configured)
|
||||
print_start += sprintf(print_start, ",UDP%c", rule->bool_accept_udp ? '+' : '-');
|
||||
if(rule->key.bool_icmp_configured)
|
||||
print_start += sprintf(print_start, ",ICMP%c", rule->bool_accept_icmp ? '+' : '-');
|
||||
return buf;
|
||||
}
|
||||
|
||||
typedef struct filter_rule_pair_cache
|
||||
{
|
||||
packet_address_proto_info_t key;
|
||||
|
||||
uint8_t bool_allow_traffic;
|
||||
|
||||
uint32_t active_count;
|
||||
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} filter_rule_pair_cache_t;
|
||||
|
||||
uint8_t march_cidr_and_address(in_addr_t network, uint8_t net_bitlen, in_addr_t ip_addr)
|
||||
{
|
||||
in_addr_t mask = 0, ip_addr_network = 0;
|
||||
network = ntohl(network), ip_addr = ntohl(ip_addr);
|
||||
uint32_t mask1 = net_bitlen != 0 ? ((~mask) << (32u-net_bitlen)) : 0;
|
||||
ip_addr_network = ip_addr & mask1;
|
||||
if( network == ip_addr_network )
|
||||
return net_bitlen + 1; // march 0.0.0.0/0 still march success, that case return 1
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if ports march, compare cidr. if cidr ok, return sum of src&dst cidr net_bitlen. means always select larger net_bitlen record when multi record is marched.
|
||||
uint8_t march_rule_and_cache_key(filter_rule_key_t *rule_key, packet_address_proto_info_t *pkt_addr_info)
|
||||
{
|
||||
// march failed if proto is not configured at the rule.
|
||||
switch (pkt_addr_info->proto)
|
||||
{
|
||||
case FPP_ICMP:
|
||||
if(!rule_key->bool_icmp_configured) return 0;
|
||||
break;
|
||||
case FPP_UDP:
|
||||
if(!rule_key->bool_udp_configured) return 0;
|
||||
break;
|
||||
case FPP_TCP:
|
||||
if(!rule_key->bool_tcp_configured) return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore ports for ICMP proto.
|
||||
if( pkt_addr_info->proto == FPP_ICMP || (rule_key->src_port_range.start_port <= pkt_addr_info->src_port
|
||||
&& pkt_addr_info->src_port <= rule_key->src_port_range.end_port
|
||||
&& rule_key->dst_port_range.start_port <= pkt_addr_info->dst_port
|
||||
&& pkt_addr_info->dst_port <= rule_key->dst_port_range.end_port) )
|
||||
{
|
||||
uint8_t march_src_score = march_cidr_and_address(rule_key->src_net_cidr, rule_key->src_net_bit_len, pkt_addr_info->src_ip);
|
||||
uint8_t march_dst_score = march_cidr_and_address(rule_key->dst_net_cidr, rule_key->dst_net_bit_len, pkt_addr_info->dst_ip);
|
||||
if( march_src_score > 0 && march_dst_score > 0 )
|
||||
return march_src_score + march_dst_score;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
filter_rule_t* get_filter_rule(filter_rule_t **rules, packet_address_proto_info_t *pkt_addr_info)
|
||||
{
|
||||
filter_rule_t *item = 0, *tmp = 0, *marched_rule = 0;
|
||||
int march_score = 0;
|
||||
|
||||
HASH_ITER(hh, *rules, item, tmp) {
|
||||
/* ... it is safe to delete and free s here */
|
||||
uint8_t cur_march_score = march_rule_and_cache_key(&(item->key), pkt_addr_info);
|
||||
if( cur_march_score > march_score )
|
||||
{
|
||||
marched_rule = item;
|
||||
march_score = cur_march_score;
|
||||
}
|
||||
}
|
||||
return marched_rule;
|
||||
}
|
||||
|
||||
typedef struct network_traffic_filter_impl
|
||||
{
|
||||
n2n_verdict (*filter_packet_from_peer)(struct network_traffic_filter* filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size);
|
||||
|
||||
n2n_verdict (*filter_packet_from_tap)(struct network_traffic_filter* filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size);
|
||||
|
||||
filter_rule_t *rules;
|
||||
|
||||
filter_rule_pair_cache_t *connections_rule_cache;
|
||||
|
||||
uint32_t work_count_scene_last_clear;
|
||||
}network_traffic_filter_impl_t;
|
||||
|
||||
void update_and_clear_cache_if_need(network_traffic_filter_impl_t *filter)
|
||||
{
|
||||
if( ++(filter->work_count_scene_last_clear) > CLEAR_CACHE_EVERY_X_COUNT)
|
||||
{
|
||||
filter_rule_pair_cache_t *item = NULL, *tmp = NULL;
|
||||
HASH_ITER(hh, filter->connections_rule_cache, item, tmp) {
|
||||
/* ... it is safe to delete and free s here */
|
||||
if( item->active_count < CLAER_CACHE_ACTIVE_COUNT )
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "### DELETE filter cache %s", get_filter_packet_info_log_string(&item->key));
|
||||
HASH_DEL(filter->connections_rule_cache, item);
|
||||
free(item);
|
||||
}else{
|
||||
item->active_count = 0;
|
||||
}
|
||||
}
|
||||
filter->work_count_scene_last_clear = 0;
|
||||
}
|
||||
}
|
||||
|
||||
filter_rule_pair_cache_t* get_or_create_filter_rule_cache(network_traffic_filter_impl_t *filter, packet_address_proto_info_t *pkt_addr_info)
|
||||
{
|
||||
filter_rule_pair_cache_t* rule_cache_find_result = 0;
|
||||
HASH_FIND(hh, filter->connections_rule_cache, pkt_addr_info, sizeof(packet_address_proto_info_t), rule_cache_find_result);
|
||||
if( !rule_cache_find_result )
|
||||
{
|
||||
filter_rule_t* rule = get_filter_rule(&filter->rules, pkt_addr_info);
|
||||
if( !rule )
|
||||
return NULL;
|
||||
|
||||
rule_cache_find_result = malloc(sizeof(filter_rule_pair_cache_t));
|
||||
memset(rule_cache_find_result, 0, sizeof(filter_rule_pair_cache_t));
|
||||
rule_cache_find_result->key = *pkt_addr_info;
|
||||
switch(rule_cache_find_result->key.proto)
|
||||
{
|
||||
case FPP_ICMP:
|
||||
rule_cache_find_result->bool_allow_traffic = rule->bool_accept_icmp;
|
||||
break;
|
||||
case FPP_UDP:
|
||||
rule_cache_find_result->bool_allow_traffic = rule->bool_accept_udp;
|
||||
break;
|
||||
case FPP_TCP:
|
||||
rule_cache_find_result->bool_allow_traffic = rule->bool_accept_tcp;
|
||||
break;
|
||||
default:
|
||||
traceEvent(TRACE_WARNING, "### Generate filter rule cache failed!");
|
||||
return NULL;
|
||||
}
|
||||
traceEvent(TRACE_DEBUG, "### ADD filter cache %s", get_filter_packet_info_log_string(&rule_cache_find_result->key));
|
||||
HASH_ADD(hh, filter->connections_rule_cache, key, sizeof(packet_address_proto_info_t), rule_cache_find_result);
|
||||
}
|
||||
++(rule_cache_find_result->active_count);
|
||||
update_and_clear_cache_if_need(filter);
|
||||
return rule_cache_find_result;
|
||||
}
|
||||
|
||||
|
||||
n2n_verdict filter_packet_from_peer(network_traffic_filter_impl_t *filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size)
|
||||
{
|
||||
filter_rule_pair_cache_t *cur_pkt_rule = 0;
|
||||
packet_address_proto_info_t pkt_info;
|
||||
collect_packet_info(&pkt_info, payload, payload_size);
|
||||
cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info);
|
||||
if( cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info));
|
||||
return N2N_DROP;
|
||||
}
|
||||
return N2N_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
n2n_verdict filter_packet_from_tap(network_traffic_filter_impl_t *filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size)
|
||||
{
|
||||
filter_rule_pair_cache_t *cur_pkt_rule = 0;
|
||||
packet_address_proto_info_t pkt_info;
|
||||
collect_packet_info(&pkt_info, payload, payload_size);
|
||||
cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info);
|
||||
if( cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info));
|
||||
return N2N_DROP;
|
||||
}
|
||||
return N2N_ACCEPT;
|
||||
}
|
||||
|
||||
network_traffic_filter_t *create_network_traffic_filter() {
|
||||
network_traffic_filter_impl_t *filter = malloc(sizeof(network_traffic_filter_impl_t));
|
||||
memset(filter, 0, sizeof(network_traffic_filter_impl_t));
|
||||
filter->filter_packet_from_peer = filter_packet_from_peer;
|
||||
filter->filter_packet_from_tap = filter_packet_from_tap;
|
||||
return filter;
|
||||
}
|
||||
|
||||
void destroy_network_traffic_filter(network_traffic_filter_t *filter) {
|
||||
network_traffic_filter_impl_t *_filter = filter;
|
||||
|
||||
{
|
||||
filter_rule_t *el = 0, *tmp = 0;
|
||||
HASH_ITER(hh, _filter->rules, el, tmp)
|
||||
{
|
||||
HASH_DEL(_filter->rules, el);
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
filter_rule_pair_cache_t *el = 0, *tmp = 0;
|
||||
HASH_ITER(hh, _filter->connections_rule_cache, el, tmp)
|
||||
{
|
||||
HASH_DEL(_filter->connections_rule_cache, el);
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
|
||||
free(filter);
|
||||
}
|
||||
|
||||
void network_traffic_filter_add_rule(network_traffic_filter_t* filter, filter_rule_t* rules) {
|
||||
filter_rule_t *item=NULL, *tmp=NULL;
|
||||
HASH_ITER(hh, rules, item, tmp) {
|
||||
network_traffic_filter_impl_t *_filter = filter;
|
||||
filter_rule_t *new_rule = malloc(sizeof(filter_rule_t));
|
||||
memcpy(new_rule, item, sizeof(filter_rule_t));
|
||||
HASH_ADD(hh, _filter->rules, key, sizeof(filter_rule_key_t), new_rule);
|
||||
traceEvent(TRACE_NORMAL, "### ADD network traffic filter %s", get_filter_rule_info_log_string(new_rule));
|
||||
}
|
||||
}
|
||||
|
||||
in_addr_t get_int32_addr_from_ip_string(const char* begin, const char* next_pos_of_last_char)
|
||||
{
|
||||
char buf[16] = {0};
|
||||
if( next_pos_of_last_char - begin > 15 ) {
|
||||
traceEvent(TRACE_WARNING, "Internal Error");
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf, begin, next_pos_of_last_char - begin);
|
||||
struct in_addr addr;
|
||||
if(1 == inet_aton(buf, &addr) )
|
||||
return addr.s_addr;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_int32_from_number_string(const char* begin, const char* next_pos_of_last_char)
|
||||
{
|
||||
char buf[6] = {0};
|
||||
if( next_pos_of_last_char - begin > 5 ) // max is 65535, 5 char
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Internal Error");
|
||||
return 0;
|
||||
}
|
||||
memcpy(buf, begin, next_pos_of_last_char - begin);
|
||||
return atoi(buf);
|
||||
}
|
||||
|
||||
void process_traffic_filter_proto(const char* begin, const char* next_pos_of_last_char, filter_rule_t *rule_struct)
|
||||
{
|
||||
char buf[6] = {0};
|
||||
if( next_pos_of_last_char - begin > 5 ) // max length str is "ICMP+", 5 char
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Internal Error");
|
||||
}
|
||||
memcpy(buf, begin, next_pos_of_last_char - begin);
|
||||
|
||||
if(strstr(buf, "TCP")){
|
||||
rule_struct->key.bool_tcp_configured = 1;
|
||||
rule_struct->bool_accept_tcp = buf[3] == '+';
|
||||
}
|
||||
else if(strstr(buf, "UDP")){
|
||||
rule_struct->key.bool_udp_configured = 1;
|
||||
rule_struct->bool_accept_udp = buf[3] == '+';
|
||||
}
|
||||
else if(strstr(buf, "ICMP"))
|
||||
{
|
||||
rule_struct->key.bool_icmp_configured = 1;
|
||||
rule_struct->bool_accept_icmp = buf[4] == '+';
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_WARNING, "Invalid Proto : %s", buf);
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FPS_SRC_NET = 1,
|
||||
FPS_SRC_NET_BIT_LEN,
|
||||
FPS_SRC_PORT_SINGLE,
|
||||
FPS_SRC_PORT_RANGE,
|
||||
FPS_SRC_PORT_START,
|
||||
FPS_SRC_PORT_END,
|
||||
FPS_DST_NET,
|
||||
FPS_DST_NET_BIT_LEN,
|
||||
FPS_DST_PORT_SINGLE,
|
||||
FPS_DST_PORT_RANGE,
|
||||
FPS_DST_PORT_START,
|
||||
FPS_DST_PORT_END,
|
||||
FPS_PROTO
|
||||
} filter_process_stage;
|
||||
|
||||
uint8_t process_traffic_filter_rule_str(const char *rule_str, filter_rule_t *rule_struct) {
|
||||
const char *cur_pos = rule_str, *stage_begin_pos = rule_str;
|
||||
filter_process_stage stage = FPS_SRC_NET;
|
||||
while(1)
|
||||
{
|
||||
switch(stage)
|
||||
{
|
||||
case FPS_SRC_NET:
|
||||
{
|
||||
if( (*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.')
|
||||
; // Normal FPS_SRC_NET, next char
|
||||
else if( *cur_pos == '/' ) {
|
||||
// FPS_SRC_NET finish, next is FPS_SRC_NET_BIT_LEN
|
||||
rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_SRC_NET_BIT_LEN;
|
||||
}else if( *cur_pos == ':') {
|
||||
// FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE
|
||||
rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.src_net_bit_len = 32;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
if( *(cur_pos+1) == '[' )
|
||||
stage = FPS_SRC_PORT_RANGE;
|
||||
else
|
||||
stage = FPS_SRC_PORT_SINGLE;
|
||||
}else if( *cur_pos == ','){
|
||||
// FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), ignore FPS_SRC_PORT(default all),
|
||||
// next is FPS_DST_NET
|
||||
rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.src_net_bit_len = 32;
|
||||
rule_struct->key.src_port_range.start_port = 0;
|
||||
rule_struct->key.src_port_range.end_port = 65535;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_NET;
|
||||
} else {
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_SRC_NET_BIT_LEN:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_SRC_NET_BIT_LEN, next char
|
||||
else if( *cur_pos == ':') {
|
||||
// FPS_SRC_NET_BIT_LEN finish, next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE
|
||||
rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
if( *(cur_pos+1) == '[' )
|
||||
stage = FPS_SRC_PORT_RANGE;
|
||||
else
|
||||
stage = FPS_SRC_PORT_SINGLE;
|
||||
}else if( *cur_pos == ','){
|
||||
// FPS_SRC_NET_BIT_LEN finish, ignore FPS_SRC_PORT(default all), next is FPS_DST_NET
|
||||
rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);;
|
||||
rule_struct->key.src_port_range.start_port = 0;
|
||||
rule_struct->key.src_port_range.end_port = 65535;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_NET;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_SRC_PORT_SINGLE:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_SRC_PORT_SINGLE, next char
|
||||
else if(*cur_pos == ','){
|
||||
// FPS_SRC_PORT_SINGLE finish, next is FPS_DST_NET
|
||||
rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.src_port_range.end_port = rule_struct->key.src_port_range.start_port;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_NET;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_SRC_PORT_RANGE:
|
||||
{
|
||||
if(*cur_pos == '[')
|
||||
{
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_SRC_PORT_START;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_SRC_PORT_START:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_SRC_PORT_START, next char
|
||||
else if(*cur_pos == ',')
|
||||
{
|
||||
// FPS_SRC_PORT_START finish, next is FPS_SRC_PORT_END
|
||||
rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_SRC_PORT_END;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_SRC_PORT_END:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_SRC_PORT_END, next char
|
||||
else if(*cur_pos == ']' && *(cur_pos + 1) == ',')
|
||||
{
|
||||
// FPS_SRC_PORT_END finish, next is FPS_DST_NET
|
||||
rule_struct->key.src_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 2;
|
||||
stage = FPS_DST_NET;
|
||||
++cur_pos; //skip next char ','
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_NET:
|
||||
{
|
||||
if( (*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.')
|
||||
; // Normal FPS_DST_NET, next char
|
||||
else if( *cur_pos == '/' ) {
|
||||
// FPS_DST_NET finish, next is FPS_DST_NET_BIT_LEN
|
||||
rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_NET_BIT_LEN;
|
||||
}else if( *cur_pos == ':') {
|
||||
// FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE
|
||||
rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.dst_net_bit_len = 32;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
if( *(cur_pos+1) == '[' )
|
||||
stage = FPS_DST_PORT_RANGE;
|
||||
else
|
||||
stage = FPS_DST_PORT_SINGLE;
|
||||
}else if( *cur_pos == ',' || *cur_pos == 0){
|
||||
// FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), ignore FPS_DST_PORT(default all),
|
||||
// next is FPS_PROTO
|
||||
rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.dst_net_bit_len = 32;
|
||||
rule_struct->key.dst_port_range.start_port = 0;
|
||||
rule_struct->key.dst_port_range.end_port = 65535;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_PROTO;
|
||||
} else {
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_NET_BIT_LEN:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_DST_NET_BIT_LEN, next char
|
||||
else if( *cur_pos == ':') {
|
||||
// FPS_DST_NET_BIT_LEN finish, next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE
|
||||
rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
if( *(cur_pos+1) == '[' )
|
||||
stage = FPS_DST_PORT_RANGE;
|
||||
else
|
||||
stage = FPS_DST_PORT_SINGLE;
|
||||
}else if( *cur_pos == ',' || *cur_pos == 0){
|
||||
// FPS_DST_NET_BIT_LEN finish, ignore FPS_DST_PORT(default all), next is FPS_PROTO
|
||||
rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);;
|
||||
rule_struct->key.dst_port_range.start_port = 0;
|
||||
rule_struct->key.dst_port_range.end_port = 65535;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_PROTO;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_PORT_SINGLE:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_DST_PORT_SINGLE, next char
|
||||
else if(*cur_pos == ',' || *cur_pos == 0){
|
||||
// FPS_DST_PORT_SINGLE finish, next is FPS_PROTO
|
||||
rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
rule_struct->key.dst_port_range.end_port = rule_struct->key.dst_port_range.start_port;
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_PROTO;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_PORT_RANGE:
|
||||
{
|
||||
if(*cur_pos == '[')
|
||||
{
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_PORT_START;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_PORT_START:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_DST_PORT_START, next char
|
||||
else if(*cur_pos == ',')
|
||||
{
|
||||
// FPS_DST_PORT_START finish, next is FPS_DST_PORT_END
|
||||
rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage_begin_pos = cur_pos + 1;
|
||||
stage = FPS_DST_PORT_END;
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_DST_PORT_END:
|
||||
{
|
||||
if( *cur_pos >= '0' && *cur_pos <= '9')
|
||||
; // Normal FPS_DST_PORT_END, next char
|
||||
else if(*cur_pos == ']')
|
||||
{
|
||||
// FPS_DST_PORT_END finish, next is FPS_PROTO
|
||||
rule_struct->key.dst_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos);
|
||||
stage = FPS_PROTO;
|
||||
if(*(cur_pos + 1) == ',') {
|
||||
stage_begin_pos = cur_pos + 2;
|
||||
++cur_pos; //skip next char ','
|
||||
}else if(*(cur_pos + 1) != 0){
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FPS_PROTO:
|
||||
{
|
||||
if(*cur_pos != '-' && *cur_pos != '+' && *cur_pos != ',')
|
||||
; // Normal FPS_PROTO. next char
|
||||
else if( *cur_pos != ',' )
|
||||
{
|
||||
process_traffic_filter_proto(stage_begin_pos, cur_pos + 1, rule_struct);
|
||||
if( *(cur_pos+1) == 0 ) // end of whole rule string
|
||||
break;
|
||||
else{ // new proto info, and skip next char ','
|
||||
stage_begin_pos = cur_pos + 2;
|
||||
++cur_pos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
traceEvent(TRACE_WARNING, "Internal Error: ',' should skiped", *cur_pos, cur_pos - rule_str);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 == *cur_pos)
|
||||
break;
|
||||
++cur_pos;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user