From 90fb7801ebb4c8358ee56814279097292d6c2458 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 22 Nov 2023 01:56:24 +0100 Subject: [PATCH] netfilter_nft: rule_t: have src/dst/nat addresses and ports instead of guessing if it is remote host / external or internal address... --- miniupnpd/netfilter_nft/nftnlrdr.c | 60 ++++++++++++------------- miniupnpd/netfilter_nft/nftnlrdr_misc.c | 53 ++++++++++------------ miniupnpd/netfilter_nft/nftnlrdr_misc.h | 17 +++---- miniupnpd/netfilter_nft/nftpinhole.c | 26 +++++------ 4 files changed, 76 insertions(+), 80 deletions(-) diff --git a/miniupnpd/netfilter_nft/nftnlrdr.c b/miniupnpd/netfilter_nft/nftnlrdr.c index 262f211..5daeee7 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr.c +++ b/miniupnpd/netfilter_nft/nftnlrdr.c @@ -292,7 +292,7 @@ delete_filter_rule(const char * ifname, unsigned short port, int proto) refresh_nft_cache_filter(); 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); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); break; @@ -318,10 +318,10 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) // Delete Redirect Rule 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)) { - iaddr = p->iaddr; - iport = p->iport; + iaddr = p->nat_addr; + iport = p->nat_port; r = rule_del_handle(p); /* Todo: send bulk request */ @@ -334,8 +334,8 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) refresh_nft_cache_filter(); // Delete Forward Rule LIST_FOREACH(p, &head_filter, entry) { - if (p->eport == iport && - p->iaddr == iaddr && p->type == RULE_FILTER) { + if (p->nat_port == iport && + p->nat_addr == iaddr && p->type == RULE_FILTER) { r = rule_del_handle(p); /* Todo: send bulk request */ 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(); // Delete Peer Rule 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)) { - iaddr = p->iaddr; - iport = p->iport; + iaddr = p->daddr; + iport = p->dport; r = rule_del_handle(p); /* Todo: send bulk request */ @@ -366,8 +366,8 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) refresh_nft_cache_filter(); // Delete Forward Rule LIST_FOREACH(p, &head_filter, entry) { - if (p->eport == iport && - p->iaddr == iaddr && p->type == RULE_FILTER) { + if (p->dport == iport && + p->daddr == iaddr && p->type == RULE_FILTER) { r = rule_del_handle(p); /* Todo: send bulk request */ nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); @@ -405,18 +405,18 @@ get_peer_rule_by_index(int index, } if (eport != NULL) { - *eport = r->eport; + *eport = r->nat_port; } 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", "get_peer_rule_by_index"); } } if (iport != NULL) { - *iport = r->iport; + *iport = r->dport; } if (proto != NULL) { @@ -424,8 +424,8 @@ get_peer_rule_by_index(int index, } if (rhost != NULL) { - if (r->rhost) { - if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { + if (r->saddr) { + if (inet_ntop(AF_INET, &r->saddr, rhost, rhostlen) == NULL) { syslog(LOG_ERR, "%s: inet_ntop: %m", "get_peer_rule_by_index"); } @@ -435,7 +435,7 @@ get_peer_rule_by_index(int index, } if (rport != NULL) { - *rport = r->rport; + *rport = r->sport; } if (desc != NULL) { @@ -450,7 +450,7 @@ get_peer_rule_by_index(int index, } 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} @@ -524,18 +524,18 @@ get_redirect_rule_by_index(int index, } if (eport != NULL) { - *eport = r->eport; + *eport = r->dport; } 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", "get_redirect_rule_by_index"); } } if (iport != NULL) { - *iport = r->iport; + *iport = r->nat_port; } if (proto != NULL) { @@ -543,8 +543,8 @@ get_redirect_rule_by_index(int index, } if (rhost != NULL) { - if (r->rhost) { - if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { + if (r->saddr) { + if (inet_ntop(AF_INET, &r->saddr, rhost, rhostlen) == NULL) { syslog(LOG_ERR, "%s: inet_ntop: %m", "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) { if (p->proto == proto && - p->eport == eport) { + p->dport == eport) { - if (p->iaddr && iaddr) { - addr.s_addr = p->iaddr; + if (p->nat_addr && iaddr) { + addr.s_addr = p->nat_addr; if (inet_ntop(AF_INET, &addr, iaddr, iaddrlen) == NULL) { syslog(LOG_ERR, "%s: inet_ntop: %m", "get_nat_redirect_rule"); @@ -619,7 +619,7 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, } if (iport) - *iport = p->iport; + *iport = p->nat_port; if(timestamp != NULL) *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) { if (p->proto == proto && - startport <= p->eport && - p->eport <= endport) { + startport <= p->dport && + p->dport <= endport) { if (*number >= capacity) { capacity += 128; @@ -677,7 +677,7 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, } array = tmp; } - array[*number] = p->eport; + array[*number] = p->dport; (*number)++; } } diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.c b/miniupnpd/netfilter_nft/nftnlrdr_misc.c index 98a287a..40a71c5 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.c +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.c @@ -129,8 +129,8 @@ void print_rule_t(const char *func, int line, const rule_t *r) { fprintf(stdout, "%s[%d]: ", func, line); - printf("%s %s %d %hu => %hu\n", r->table, r->chain, (int)r->type, - r->eport, r->iport); + printf("%s %s %d %hu => %hu => %hu\n", r->table, r->chain, (int)r->type, + r->sport, r->dport, r->nat_port); } /* 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); if (reg_val_ptr != NULL) { - if (r->nat_type == NFT_NAT_DNAT) { - 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) { - r->eport = proto_min_val; - } + r->nat_addr = (in_addr_t)*reg_val_ptr; + if (proto_min_reg == NFT_REG_1) { + r->nat_port = proto_min_val; } } else { 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) && len == sizeof(uint16_t)) { *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) && len == sizeof(uint16_t) * 2) { *regptr = RULE_REG_TCP_SD_PORT; @@ -428,44 +426,36 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) break; case RULE_REG_IP_SRC_ADDR: if (data_len == sizeof(in_addr_t)) { - r->rhost = *(const in_addr_t *)data_val; + r->saddr = *(const in_addr_t *)data_val; } break; case RULE_REG_IP6_SRC_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; case RULE_REG_IP_DEST_ADDR: if (data_len == sizeof(in_addr_t)) { - if (r->type == RULE_FILTER) { - r->iaddr = *(const in_addr_t *)data_val; - } else { - r->rhost = *(const in_addr_t *)data_val; - } + r->daddr = *(const in_addr_t *)data_val; } break; case RULE_REG_IP6_DEST_ADDR: if (data_len == sizeof(struct in6_addr)) { - if (r->type == RULE_FILTER) { - r->iaddr6 = *(const struct in6_addr *)data_val; - } else { - r->rhost6 = *(const struct in6_addr *)data_val; - } + r->daddr6 = *(const struct in6_addr *)data_val; } break; case RULE_REG_IP_SD_ADDR: if (data_len == sizeof(in_addr_t) * 2) { const in_addr_t *addrp = (const in_addr_t *)data_val; - r->iaddr = addrp[0]; - r->rhost = addrp[1]; + r->saddr = addrp[0]; + r->daddr = addrp[1]; } break; case RULE_REG_IP6_SD_ADDR: if (data_len == sizeof(struct in6_addr) * 2) { const struct in6_addr *addrp6 = (const struct in6_addr *)data_val; - r->iaddr6 = addrp6[0]; - r->rhost6 = addrp6[1]; + r->saddr6 = addrp6[0]; + r->daddr6 = addrp6[1]; } break; 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; } 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: if (data_len == sizeof(uint16_t)) { - r->eport = ntohs(*(const uint16_t *)data_val); + r->dport = ntohs(*(const uint16_t *)data_val); } break; case RULE_REG_TCP_SD_PORT: if (data_len == sizeof(uint16_t) * 2) { const uint16_t * ports = (const uint16_t *)data_val; - r->eport = ntohs(ports[0]); - r->rport = ntohs(ports[1]); + r->sport = ntohs(ports[0]); + r->dport = ntohs(ports[1]); } break; default: diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.h b/miniupnpd/netfilter_nft/nftnlrdr_misc.h index e6ea950..b6fed92 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.h +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.h @@ -33,6 +33,7 @@ enum rule_reg_type { RULE_REG_IP6_SD_ADDR, /* source & dest */ RULE_REG_IP_PROTO, RULE_REG_IP6_PROTO, + RULE_REG_TCP_SPORT, RULE_REG_TCP_DPORT, RULE_REG_TCP_SD_PORT, /* source & dest */ RULE_REG_IMM_VAL, /* immediate */ @@ -63,14 +64,14 @@ typedef struct rule_t { uint32_t family; uint32_t ingress_ifidx; uint32_t egress_ifidx; - in_addr_t eaddr; - in_addr_t iaddr; - in_addr_t rhost; - struct in6_addr iaddr6; - struct in6_addr rhost6; - uint16_t eport; - uint16_t iport; - uint16_t rport; + in_addr_t saddr; + struct in6_addr saddr6; + uint16_t sport; + in_addr_t daddr; + struct in6_addr daddr6; + uint16_t dport; + in_addr_t nat_addr; + uint16_t nat_port; uint8_t proto; enum rule_reg_type reg1_type; enum rule_reg_type reg2_type; diff --git a/miniupnpd/netfilter_nft/nftpinhole.c b/miniupnpd/netfilter_nft/nftpinhole.c index 36ad756..bd9493f 100644 --- a/miniupnpd/netfilter_nft/nftpinhole.c +++ b/miniupnpd/netfilter_nft/nftpinhole.c @@ -153,10 +153,10 @@ find_pinhole(const char * ifname, if (p->desc_len == 0) continue; - if ((proto == p->proto) && (rem_port == p->rport) - && (0 == memcmp(&saddr, &p->rhost6, sizeof(struct in6_addr))) - && (int_port == p->iport) && - (0 == memcmp(&daddr, &p->iaddr6, sizeof(struct in6_addr)))) { + if ((proto == p->proto) && (rem_port == p->sport) + && (0 == memcmp(&saddr, &p->saddr6, sizeof(struct in6_addr))) + && (int_port == p->dport) && + (0 == memcmp(&daddr, &p->daddr6, sizeof(struct in6_addr)))) { 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); @@ -259,23 +259,23 @@ update_pinhole(unsigned short uid, unsigned int timestamp) if (0 == strcmp(tmp_label, label_start)) { /* Source IP Address */ // 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; raddr[0] = '*'; raddr[1] = '\0'; } else { - rhost_addr_p = &p->rhost6; + rhost_addr_p = &p->saddr6; inet_ntop(AF_INET6, rhost_addr_p, raddr, INET6_ADDRSTRLEN); } /* Source Port */ - rport = p->iport; + rport = p->sport; /* Destination IP Address */ - ihost_addr = p->iaddr6; + ihost_addr = p->daddr6; /* Destination Port */ - iport = p->eport; + iport = p->dport; proto = p->proto; @@ -357,23 +357,23 @@ get_pinhole_info(unsigned short uid, if (0 == strcmp(tmp_label, label_start)) { /* Source IP Address */ 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; } /* Source Port */ if (rem_port) - *rem_port = p->rport; + *rem_port = p->sport; /* Destination IP Address */ 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; } /* Destination Port */ if (int_port) - *int_port = p->eport; + *int_port = p->dport; if (proto) *proto = p->proto;