netfilter_nft: rule_t: have src/dst/nat addresses and ports

instead of guessing if it is remote host / external or internal address...
This commit is contained in:
Thomas Bernard 2023-11-22 01:56:24 +01:00
parent 25206a7a3f
commit 90fb7801eb
No known key found for this signature in database
GPG Key ID: DB511043A31ACAAF
4 changed files with 76 additions and 80 deletions

View File

@ -292,7 +292,7 @@ delete_filter_rule(const char * ifname, unsigned short port, int proto)
refresh_nft_cache_filter(); refresh_nft_cache_filter();
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) { if (p->dport == port && p->proto == proto && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
break; break;
@ -318,10 +318,10 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
// Delete Redirect Rule // Delete Redirect Rule
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
if (p->eport == eport && p->proto == proto && if (p->dport == eport && p->proto == proto &&
(p->type == RULE_NAT && p->nat_type == NFT_NAT_DNAT)) { (p->type == RULE_NAT && p->nat_type == NFT_NAT_DNAT)) {
iaddr = p->iaddr; iaddr = p->nat_addr;
iport = p->iport; iport = p->nat_port;
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
@ -334,8 +334,8 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
refresh_nft_cache_filter(); refresh_nft_cache_filter();
// Delete Forward Rule // Delete Forward Rule
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == iport && if (p->nat_port == iport &&
p->iaddr == iaddr && p->type == RULE_FILTER) { p->nat_addr == iaddr && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
@ -350,10 +350,10 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
refresh_nft_cache_peer(); refresh_nft_cache_peer();
// Delete Peer Rule // Delete Peer Rule
LIST_FOREACH(p, &head_peer, entry) { LIST_FOREACH(p, &head_peer, entry) {
if (p->eport == eport && p->proto == proto && if (p->nat_port == eport && p->proto == proto &&
(p->type == RULE_NAT && p->nat_type == NFT_NAT_SNAT)) { (p->type == RULE_NAT && p->nat_type == NFT_NAT_SNAT)) {
iaddr = p->iaddr; iaddr = p->daddr;
iport = p->iport; iport = p->dport;
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
@ -366,8 +366,8 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
refresh_nft_cache_filter(); refresh_nft_cache_filter();
// Delete Forward Rule // Delete Forward Rule
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == iport && if (p->dport == iport &&
p->iaddr == iaddr && p->type == RULE_FILTER) { p->daddr == iaddr && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
@ -405,18 +405,18 @@ get_peer_rule_by_index(int index,
} }
if (eport != NULL) { if (eport != NULL) {
*eport = r->eport; *eport = r->nat_port;
} }
if (iaddr != NULL) { if (iaddr != NULL) {
if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) { if (inet_ntop(AF_INET, &r->daddr, iaddr, iaddrlen) == NULL) {
syslog(LOG_ERR, "%s: inet_ntop: %m", syslog(LOG_ERR, "%s: inet_ntop: %m",
"get_peer_rule_by_index"); "get_peer_rule_by_index");
} }
} }
if (iport != NULL) { if (iport != NULL) {
*iport = r->iport; *iport = r->dport;
} }
if (proto != NULL) { if (proto != NULL) {
@ -424,8 +424,8 @@ get_peer_rule_by_index(int index,
} }
if (rhost != NULL) { if (rhost != NULL) {
if (r->rhost) { if (r->saddr) {
if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { if (inet_ntop(AF_INET, &r->saddr, rhost, rhostlen) == NULL) {
syslog(LOG_ERR, "%s: inet_ntop: %m", syslog(LOG_ERR, "%s: inet_ntop: %m",
"get_peer_rule_by_index"); "get_peer_rule_by_index");
} }
@ -435,7 +435,7 @@ get_peer_rule_by_index(int index,
} }
if (rport != NULL) { if (rport != NULL) {
*rport = r->rport; *rport = r->sport;
} }
if (desc != NULL) { if (desc != NULL) {
@ -450,7 +450,7 @@ get_peer_rule_by_index(int index,
} }
if (timestamp) { if (timestamp) {
*timestamp = get_timestamp(r->eport, r->proto); *timestamp = get_timestamp(r->dport, r->proto);
} }
/* /*
* TODO: Implement counter in case of add {nat,filter} * TODO: Implement counter in case of add {nat,filter}
@ -524,18 +524,18 @@ get_redirect_rule_by_index(int index,
} }
if (eport != NULL) { if (eport != NULL) {
*eport = r->eport; *eport = r->dport;
} }
if (iaddr != NULL) { if (iaddr != NULL) {
if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) { if (inet_ntop(AF_INET, &r->nat_addr, iaddr, iaddrlen) == NULL) {
syslog(LOG_ERR, "%s: inet_ntop: %m", syslog(LOG_ERR, "%s: inet_ntop: %m",
"get_redirect_rule_by_index"); "get_redirect_rule_by_index");
} }
} }
if (iport != NULL) { if (iport != NULL) {
*iport = r->iport; *iport = r->nat_port;
} }
if (proto != NULL) { if (proto != NULL) {
@ -543,8 +543,8 @@ get_redirect_rule_by_index(int index,
} }
if (rhost != NULL) { if (rhost != NULL) {
if (r->rhost) { if (r->saddr) {
if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { if (inet_ntop(AF_INET, &r->saddr, rhost, rhostlen) == NULL) {
syslog(LOG_ERR, "%s: inet_ntop: %m", syslog(LOG_ERR, "%s: inet_ntop: %m",
"get_redirect_rule_by_index"); "get_redirect_rule_by_index");
} }
@ -604,10 +604,10 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
if (p->proto == proto && if (p->proto == proto &&
p->eport == eport) { p->dport == eport) {
if (p->iaddr && iaddr) { if (p->nat_addr && iaddr) {
addr.s_addr = p->iaddr; addr.s_addr = p->nat_addr;
if (inet_ntop(AF_INET, &addr, iaddr, iaddrlen) == NULL) { if (inet_ntop(AF_INET, &addr, iaddr, iaddrlen) == NULL) {
syslog(LOG_ERR, "%s: inet_ntop: %m", syslog(LOG_ERR, "%s: inet_ntop: %m",
"get_nat_redirect_rule"); "get_nat_redirect_rule");
@ -619,7 +619,7 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
} }
if (iport) if (iport)
*iport = p->iport; *iport = p->nat_port;
if(timestamp != NULL) if(timestamp != NULL)
*timestamp = get_timestamp(eport, proto); *timestamp = get_timestamp(eport, proto);
@ -659,8 +659,8 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
if (p->proto == proto && if (p->proto == proto &&
startport <= p->eport && startport <= p->dport &&
p->eport <= endport) { p->dport <= endport) {
if (*number >= capacity) { if (*number >= capacity) {
capacity += 128; capacity += 128;
@ -677,7 +677,7 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
} }
array = tmp; array = tmp;
} }
array[*number] = p->eport; array[*number] = p->dport;
(*number)++; (*number)++;
} }
} }

View File

@ -129,8 +129,8 @@ void
print_rule_t(const char *func, int line, const rule_t *r) print_rule_t(const char *func, int line, const rule_t *r)
{ {
fprintf(stdout, "%s[%d]: ", func, line); fprintf(stdout, "%s[%d]: ", func, line);
printf("%s %s %d %hu => %hu\n", r->table, r->chain, (int)r->type, printf("%s %s %d %hu => %hu => %hu\n", r->table, r->chain, (int)r->type,
r->eport, r->iport); r->sport, r->dport, r->nat_port);
} }
/* print out the "filter" and "nat" tables */ /* print out the "filter" and "nat" tables */
@ -300,14 +300,9 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r)
} }
reg_val_ptr = get_reg_val_ptr(r, addr_min_reg); reg_val_ptr = get_reg_val_ptr(r, addr_min_reg);
if (reg_val_ptr != NULL) { if (reg_val_ptr != NULL) {
if (r->nat_type == NFT_NAT_DNAT) { r->nat_addr = (in_addr_t)*reg_val_ptr;
r->iaddr = (in_addr_t)*reg_val_ptr;
r->iport = proto_min_val;
} else if (r->nat_type == NFT_NAT_SNAT) {
r->eaddr = (in_addr_t)*reg_val_ptr;
if (proto_min_reg == NFT_REG_1) { if (proto_min_reg == NFT_REG_1) {
r->eport = proto_min_val; r->nat_port = proto_min_val;
}
} }
} else { } else {
syslog(LOG_ERR, "%s: invalid addr_min_reg %u", "parse_rule_nat", addr_min_reg); syslog(LOG_ERR, "%s: invalid addr_min_reg %u", "parse_rule_nat", addr_min_reg);
@ -371,6 +366,9 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r)
if (offset == offsetof(struct tcphdr, dest) && if (offset == offsetof(struct tcphdr, dest) &&
len == sizeof(uint16_t)) { len == sizeof(uint16_t)) {
*regptr = RULE_REG_TCP_DPORT; *regptr = RULE_REG_TCP_DPORT;
} else if (offset == offsetof(struct tcphdr, source) &&
len == sizeof(uint16_t)) {
*regptr = RULE_REG_TCP_SPORT;
} else if (offset == offsetof(struct tcphdr, source) && } else if (offset == offsetof(struct tcphdr, source) &&
len == sizeof(uint16_t) * 2) { len == sizeof(uint16_t) * 2) {
*regptr = RULE_REG_TCP_SD_PORT; *regptr = RULE_REG_TCP_SD_PORT;
@ -428,44 +426,36 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r)
break; break;
case RULE_REG_IP_SRC_ADDR: case RULE_REG_IP_SRC_ADDR:
if (data_len == sizeof(in_addr_t)) { if (data_len == sizeof(in_addr_t)) {
r->rhost = *(const in_addr_t *)data_val; r->saddr = *(const in_addr_t *)data_val;
} }
break; break;
case RULE_REG_IP6_SRC_ADDR: case RULE_REG_IP6_SRC_ADDR:
if (data_len == sizeof(struct in6_addr)) { if (data_len == sizeof(struct in6_addr)) {
r->rhost6 = *(const struct in6_addr *)data_val; r->saddr6 = *(const struct in6_addr *)data_val;
} }
break; break;
case RULE_REG_IP_DEST_ADDR: case RULE_REG_IP_DEST_ADDR:
if (data_len == sizeof(in_addr_t)) { if (data_len == sizeof(in_addr_t)) {
if (r->type == RULE_FILTER) { r->daddr = *(const in_addr_t *)data_val;
r->iaddr = *(const in_addr_t *)data_val;
} else {
r->rhost = *(const in_addr_t *)data_val;
}
} }
break; break;
case RULE_REG_IP6_DEST_ADDR: case RULE_REG_IP6_DEST_ADDR:
if (data_len == sizeof(struct in6_addr)) { if (data_len == sizeof(struct in6_addr)) {
if (r->type == RULE_FILTER) { r->daddr6 = *(const struct in6_addr *)data_val;
r->iaddr6 = *(const struct in6_addr *)data_val;
} else {
r->rhost6 = *(const struct in6_addr *)data_val;
}
} }
break; break;
case RULE_REG_IP_SD_ADDR: case RULE_REG_IP_SD_ADDR:
if (data_len == sizeof(in_addr_t) * 2) { if (data_len == sizeof(in_addr_t) * 2) {
const in_addr_t *addrp = (const in_addr_t *)data_val; const in_addr_t *addrp = (const in_addr_t *)data_val;
r->iaddr = addrp[0]; r->saddr = addrp[0];
r->rhost = addrp[1]; r->daddr = addrp[1];
} }
break; break;
case RULE_REG_IP6_SD_ADDR: case RULE_REG_IP6_SD_ADDR:
if (data_len == sizeof(struct in6_addr) * 2) { if (data_len == sizeof(struct in6_addr) * 2) {
const struct in6_addr *addrp6 = (const struct in6_addr *)data_val; const struct in6_addr *addrp6 = (const struct in6_addr *)data_val;
r->iaddr6 = addrp6[0]; r->saddr6 = addrp6[0];
r->rhost6 = addrp6[1]; r->daddr6 = addrp6[1];
} }
break; break;
case RULE_REG_IP_PROTO: case RULE_REG_IP_PROTO:
@ -474,16 +464,21 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r)
r->proto = *(const uint8_t *)data_val; r->proto = *(const uint8_t *)data_val;
} }
break; break;
case RULE_REG_TCP_SPORT:
if (data_len == sizeof(uint16_t)) {
r->sport = ntohs(*(const uint16_t *)data_val);
}
break;
case RULE_REG_TCP_DPORT: case RULE_REG_TCP_DPORT:
if (data_len == sizeof(uint16_t)) { if (data_len == sizeof(uint16_t)) {
r->eport = ntohs(*(const uint16_t *)data_val); r->dport = ntohs(*(const uint16_t *)data_val);
} }
break; break;
case RULE_REG_TCP_SD_PORT: case RULE_REG_TCP_SD_PORT:
if (data_len == sizeof(uint16_t) * 2) { if (data_len == sizeof(uint16_t) * 2) {
const uint16_t * ports = (const uint16_t *)data_val; const uint16_t * ports = (const uint16_t *)data_val;
r->eport = ntohs(ports[0]); r->sport = ntohs(ports[0]);
r->rport = ntohs(ports[1]); r->dport = ntohs(ports[1]);
} }
break; break;
default: default:

View File

@ -33,6 +33,7 @@ enum rule_reg_type {
RULE_REG_IP6_SD_ADDR, /* source & dest */ RULE_REG_IP6_SD_ADDR, /* source & dest */
RULE_REG_IP_PROTO, RULE_REG_IP_PROTO,
RULE_REG_IP6_PROTO, RULE_REG_IP6_PROTO,
RULE_REG_TCP_SPORT,
RULE_REG_TCP_DPORT, RULE_REG_TCP_DPORT,
RULE_REG_TCP_SD_PORT, /* source & dest */ RULE_REG_TCP_SD_PORT, /* source & dest */
RULE_REG_IMM_VAL, /* immediate */ RULE_REG_IMM_VAL, /* immediate */
@ -63,14 +64,14 @@ typedef struct rule_t {
uint32_t family; uint32_t family;
uint32_t ingress_ifidx; uint32_t ingress_ifidx;
uint32_t egress_ifidx; uint32_t egress_ifidx;
in_addr_t eaddr; in_addr_t saddr;
in_addr_t iaddr; struct in6_addr saddr6;
in_addr_t rhost; uint16_t sport;
struct in6_addr iaddr6; in_addr_t daddr;
struct in6_addr rhost6; struct in6_addr daddr6;
uint16_t eport; uint16_t dport;
uint16_t iport; in_addr_t nat_addr;
uint16_t rport; uint16_t nat_port;
uint8_t proto; uint8_t proto;
enum rule_reg_type reg1_type; enum rule_reg_type reg1_type;
enum rule_reg_type reg2_type; enum rule_reg_type reg2_type;

View File

@ -153,10 +153,10 @@ find_pinhole(const char * ifname,
if (p->desc_len == 0) if (p->desc_len == 0)
continue; continue;
if ((proto == p->proto) && (rem_port == p->rport) if ((proto == p->proto) && (rem_port == p->sport)
&& (0 == memcmp(&saddr, &p->rhost6, sizeof(struct in6_addr))) && (0 == memcmp(&saddr, &p->saddr6, sizeof(struct in6_addr)))
&& (int_port == p->iport) && && (int_port == p->dport) &&
(0 == memcmp(&daddr, &p->iaddr6, sizeof(struct in6_addr)))) { (0 == memcmp(&daddr, &p->daddr6, sizeof(struct in6_addr)))) {
if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) { if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);
@ -259,23 +259,23 @@ update_pinhole(unsigned short uid, unsigned int timestamp)
if (0 == strcmp(tmp_label, label_start)) { if (0 == strcmp(tmp_label, label_start)) {
/* Source IP Address */ /* Source IP Address */
// Check if empty // Check if empty
if (0 == memcmp(&rhost_addr, &p->rhost6, sizeof(struct in6_addr))) { if (0 == memcmp(&rhost_addr, &p->saddr6, sizeof(struct in6_addr))) {
rhost_addr_p = NULL; rhost_addr_p = NULL;
raddr[0] = '*'; raddr[0] = '*';
raddr[1] = '\0'; raddr[1] = '\0';
} else { } else {
rhost_addr_p = &p->rhost6; rhost_addr_p = &p->saddr6;
inet_ntop(AF_INET6, rhost_addr_p, raddr, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, rhost_addr_p, raddr, INET6_ADDRSTRLEN);
} }
/* Source Port */ /* Source Port */
rport = p->iport; rport = p->sport;
/* Destination IP Address */ /* Destination IP Address */
ihost_addr = p->iaddr6; ihost_addr = p->daddr6;
/* Destination Port */ /* Destination Port */
iport = p->eport; iport = p->dport;
proto = p->proto; proto = p->proto;
@ -357,23 +357,23 @@ get_pinhole_info(unsigned short uid,
if (0 == strcmp(tmp_label, label_start)) { if (0 == strcmp(tmp_label, label_start)) {
/* Source IP Address */ /* Source IP Address */
if (rem_host && (rem_host[0] != '\0')) { if (rem_host && (rem_host[0] != '\0')) {
if(inet_ntop(AF_INET6, &p->rhost6, rem_host, rem_hostlen) == NULL) if(inet_ntop(AF_INET6, &p->saddr6, rem_host, rem_hostlen) == NULL)
return -1; return -1;
} }
/* Source Port */ /* Source Port */
if (rem_port) if (rem_port)
*rem_port = p->rport; *rem_port = p->sport;
/* Destination IP Address */ /* Destination IP Address */
if (int_client) { if (int_client) {
if(inet_ntop(AF_INET6, &p->iaddr6, int_client, int_clientlen) == NULL) if(inet_ntop(AF_INET6, &p->daddr6, int_client, int_clientlen) == NULL)
return -1; return -1;
} }
/* Destination Port */ /* Destination Port */
if (int_port) if (int_port)
*int_port = p->eport; *int_port = p->dport;
if (proto) if (proto)
*proto = p->proto; *proto = p->proto;