diff options
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.h | 5 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 60 | ||||
-rw-r--r-- | sys/netinet/ip_fw2.c | 548 | ||||
-rw-r--r-- | sys/netinet/ip_fw_pfil.c | 6 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 4 |
5 files changed, 621 insertions, 2 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 570ed33..321877c 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -410,6 +410,11 @@ __END_DECLS #define IP_FW_GET 54 /* get entire firewall rule chain */ #define IP_FW_RESETLOG 55 /* reset logging counters */ +#define IP_FW_NAT_CFG 56 /* add/config a nat rule */ +#define IP_FW_NAT_DEL 57 /* delete a nat rule */ +#define IP_FW_NAT_GET_CONFIG 58 /* get configuration of a nat rule */ +#define IP_FW_NAT_GET_LOG 59 /* get log of a nat rule */ + #define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ #define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ #define IP_DUMMYNET_FLUSH 62 /* flush dummynet */ diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 1f50e56..199d569 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -124,6 +124,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_TEE, /* arg1=port number */ O_FORWARD_IP, /* fwd sockaddr */ O_FORWARD_MAC, /* fwd mac */ + O_NAT, /* nope */ /* * More opcodes. @@ -307,6 +308,64 @@ typedef struct _ipfw_insn_log { u_int32_t log_left; /* how many left to log */ } ipfw_insn_log; +/* Server pool support (LSNAT). */ +struct cfg_spool { + LIST_ENTRY(cfg_spool) _next; /* chain of spool instances */ + struct in_addr addr; + u_short port; +}; + +/* Redirect modes id. */ +#define REDIR_ADDR 0x01 +#define REDIR_PORT 0x02 +#define REDIR_PROTO 0x04 + +/* Nat redirect configuration. */ +struct cfg_redir { + LIST_ENTRY(cfg_redir) _next; /* chain of redir instances */ + u_int16_t mode; /* type of redirect mode */ + struct in_addr laddr; /* local ip address */ + struct in_addr paddr; /* public ip address */ + struct in_addr raddr; /* remote ip address */ + u_short lport; /* local port */ + u_short pport; /* public port */ + u_short rport; /* remote port */ + u_short pport_cnt; /* number of public ports */ + u_short rport_cnt; /* number of remote ports */ + int proto; /* protocol: tcp/udp */ + struct alias_link **alink; + /* num of entry in spool chain */ + u_int16_t spool_cnt; + /* chain of spool instances */ + LIST_HEAD(spool_chain, cfg_spool) spool_chain; +}; + +#define NAT_BUF_LEN 1024 +/* Nat configuration data struct. */ +struct cfg_nat { + /* chain of nat instances */ + LIST_ENTRY(cfg_nat) _next; + int id; /* nat id */ + struct in_addr ip; /* nat ip address */ + char if_name[IF_NAMESIZE]; /* interface name */ + int mode; /* aliasing mode */ + struct libalias *lib; /* libalias instance */ + /* number of entry in spool chain */ + int redir_cnt; + /* chain of redir instances */ + LIST_HEAD(redir_chain, cfg_redir) redir_chain; +}; + +#define SOF_NAT sizeof(struct cfg_nat) +#define SOF_REDIR sizeof(struct cfg_redir) +#define SOF_SPOOL sizeof(struct cfg_spool) + +/* Nat command. */ +typedef struct _ipfw_insn_nat { + ipfw_insn o; + struct cfg_nat *nat; +} ipfw_insn_nat; + /* Apply ipv6 mask on ipv6 addr */ #define APPLY_MASK(addr,mask) \ (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \ @@ -483,6 +542,7 @@ enum { IP_FW_DUMMYNET, IP_FW_NETGRAPH, IP_FW_NGTEE, + IP_FW_NAT, }; /* flags for divert mtag */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 591e6ff..070de18 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -47,6 +47,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/condvar.h> +#include <sys/eventhandler.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/kernel.h> @@ -84,6 +85,8 @@ #include <netinet/udp_var.h> #include <netinet/sctp.h> +#include <netinet/libalias/alias.h> +#include <netinet/libalias/alias_local.h> #include <netgraph/ng_ipfw.h> #include <altq/if_altq.h> @@ -138,6 +141,7 @@ struct ip_fw_ugid { struct ip_fw_chain { struct ip_fw *rules; /* list of rules */ struct ip_fw *reap; /* list of rules to reap */ + LIST_HEAD(, cfg_nat) nat; /* list of nat entries */ struct radix_node_head *tables[IPFW_TABLES_MAX]; struct rwlock rwmtx; }; @@ -303,6 +307,7 @@ static struct sysctl_oid *ip6_fw_sysctl_tree; #endif /* INET6 */ #endif /* SYSCTL_NODE */ +MODULE_DEPEND(ipfw, libalias, 1, 1, 1); static int fw_deny_unknown_exthdrs = 1; @@ -861,6 +866,9 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, snprintf(SNPARGS(action2, 0), "Ngtee %d", cmd->arg1); break; + case O_NAT: + action = "Nat"; + break; default: action = "UNKNOWN"; break; @@ -2028,6 +2036,178 @@ check_uidgid(ipfw_insn_u32 *insn, return match; } +static eventhandler_tag ifaddr_event_tag; + +static void +ifaddr_change(void *arg __unused, struct ifnet *ifp) { + struct cfg_nat *ptr; + struct ifaddr *ifa; + + IPFW_WLOCK(&layer3_chain); + /* Check every nat entry... */ + LIST_FOREACH(ptr, &layer3_chain.nat, _next) { + /* ...using nic 'ifp->if_xname' as dynamic alias address. */ + if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) == 0) { + mtx_lock(&ifp->if_addr_mtx); + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ptr->ip = ((struct sockaddr_in *) + (ifa->ifa_addr))->sin_addr; + LibAliasSetAddress(ptr->lib, ptr->ip); + } + mtx_unlock(&ifp->if_addr_mtx); + } + } + IPFW_WUNLOCK(&layer3_chain); +} + +static void +flush_nat_ptrs(const int i) { + struct ip_fw *rule; + + IPFW_WLOCK_ASSERT(&layer3_chain); + for (rule = layer3_chain.rules; rule; rule = rule->next) { + ipfw_insn_nat *cmd = (ipfw_insn_nat *)ACTION_PTR(rule); + if (cmd->o.opcode != O_NAT) + continue; + if (cmd->nat != NULL && cmd->nat->id == i) + cmd->nat = NULL; + } +} + +static struct cfg_nat * +lookup_nat(const int i) { + struct cfg_nat *ptr; + + LIST_FOREACH(ptr, &layer3_chain.nat, _next) + if (ptr->id == i) + return(ptr); + return (NULL); +} + +#define HOOK_NAT(b, p) do { \ + IPFW_WLOCK_ASSERT(&layer3_chain); \ + LIST_INSERT_HEAD(b, p, _next); \ +} while (0) + +#define UNHOOK_NAT(p) do { \ + IPFW_WLOCK_ASSERT(&layer3_chain); \ + LIST_REMOVE(p, _next); \ +} while (0) + +#define HOOK_REDIR(b, p) do { \ + LIST_INSERT_HEAD(b, p, _next); \ +} while (0) + +#define HOOK_SPOOL(b, p) do { \ + LIST_INSERT_HEAD(b, p, _next); \ +} while (0) + +static void +del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head) { + struct cfg_redir *r, *tmp_r; + struct cfg_spool *s, *tmp_s; + int i, num; + + LIST_FOREACH_SAFE(r, head, _next, tmp_r) { + num = 1; /* Number of alias_link to delete. */ + switch (r->mode) { + case REDIR_PORT: + num = r->pport_cnt; + /* FALLTHROUGH */ + case REDIR_ADDR: + case REDIR_PROTO: + /* Delete all libalias redirect entry. */ + for (i = 0; i < num; i++) + LibAliasRedirectDelete(n->lib, r->alink[i]); + /* Del spool cfg if any. */ + LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) { + LIST_REMOVE(s, _next); + free(s, M_IPFW); + } + free(r->alink, M_IPFW); + LIST_REMOVE(r, _next); + free(r, M_IPFW); + break; + default: + printf("unknown redirect mode: %u\n", r->mode); + /* XXX - panic?!?!? */ + break; + } + } +} + +static int +add_redir_spool_cfg(char *buf, struct cfg_nat *ptr) { + struct cfg_redir *r, *ser_r; + struct cfg_spool *s, *ser_s; + int cnt, off, i; + char *panic_err; + + for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) { + ser_r = (struct cfg_redir *)&buf[off]; + r = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO); + memcpy(r, ser_r, SOF_REDIR); + LIST_INIT(&r->spool_chain); + off += SOF_REDIR; + r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt, + M_IPFW, M_WAITOK | M_ZERO); + switch (r->mode) { + case REDIR_ADDR: + r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr, + r->paddr); + break; + case REDIR_PORT: + for (i = 0 ; i < r->pport_cnt; i++) { + /* If remotePort is all ports, set it to 0. */ + u_short remotePortCopy = r->rport + i; + if (r->rport_cnt == 1 && r->rport == 0) + remotePortCopy = 0; + r->alink[i] = LibAliasRedirectPort(ptr->lib, + r->laddr, htons(r->lport + i), r->raddr, + htons(remotePortCopy), r->paddr, + htons(r->pport + i), r->proto); + if (r->alink[i] == NULL) { + r->alink[0] = NULL; + break; + } + } + break; + case REDIR_PROTO: + r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr, + r->raddr, r->paddr, r->proto); + break; + default: + printf("unknown redirect mode: %u\n", r->mode); + break; + } + if (r->alink[0] == NULL) { + panic_err = "LibAliasRedirect* returned NULL"; + goto bad; + } else /* LSNAT handling. */ + for (i = 0; i < r->spool_cnt; i++) { + ser_s = (struct cfg_spool *)&buf[off]; + s = malloc(SOF_REDIR, M_IPFW, + M_WAITOK | M_ZERO); + memcpy(s, ser_s, SOF_SPOOL); + LibAliasAddServer(ptr->lib, r->alink[0], + s->addr, htons(s->port)); + off += SOF_SPOOL; + /* Hook spool entry. */ + HOOK_SPOOL(&r->spool_chain, s); + } + /* And finally hook this redir entry. */ + HOOK_REDIR(&ptr->redir_chain, r); + } + return (1); +bad: + /* something really bad happened: panic! */ + panic("%s\n", panic_err); +} + /* * The main check routine for the firewall. * @@ -3257,6 +3437,177 @@ check_body: IP_FW_NETGRAPH : IP_FW_NGTEE; goto done; + case O_NAT: { + struct cfg_nat *t; + struct mbuf *mcl; + /* XXX - libalias duct tape */ + int ldt; + char *c; + + ldt = 0; + args->rule = f; /* Report matching rule. */ + retval = 0; + t = ((ipfw_insn_nat *)cmd)->nat; + if (t == NULL) { + t = lookup_nat(cmd->arg1); + if (t == NULL) { + retval = IP_FW_DENY; + goto done; + } else + ((ipfw_insn_nat *)cmd)->nat = + t; + } + if ((mcl = m_megapullup(m, m->m_pkthdr.len)) == + NULL) + goto badnat; + ip = mtod(mcl, struct ip *); + if (args->eh == NULL) { + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + } + + /* + * XXX - Libalias checksum offload 'duct tape': + * + * locally generated packets have only + * pseudo-header checksum calculated + * and libalias will screw it[1], so + * mark them for later fix. Moreover + * there are cases when libalias + * modify tcp packet data[2], mark it + * for later fix too. + * + * [1] libalias was never meant to run + * in kernel, so it doesn't have any + * knowledge about checksum + * offloading, and it expects a packet + * with a full internet + * checksum. Unfortunately, packets + * generated locally will have just the + * pseudo header calculated, and when + * libalias tries to adjust the + * checksum it will actually screw it. + * + * [2] when libalias modify tcp's data + * content, full TCP checksum has to + * be recomputed: the problem is that + * libalias doesn't have any idea + * about checksum offloading To + * workaround this, we do not do + * checksumming in LibAlias, but only + * mark the packets in th_x2 field. If + * we receive a marked packet, we + * calculate correct checksum for it + * aware of offloading. Why such a + * terrible hack instead of + * recalculating checksum for each + * packet? Because the previous + * checksum was not checked! + * Recalculating checksums for EVERY + * packet will hide ALL transmission + * errors. Yes, marked packets still + * suffer from this problem. But, + * sigh, natd(8) has this problem, + * too. + * + * TODO: -make libalias mbuf aware (so + * it can handle delayed checksum and tso) + */ + + if (mcl->m_pkthdr.rcvif == NULL && + mcl->m_pkthdr.csum_flags & + CSUM_DELAY_DATA) + ldt = 1; + + c = mtod(mcl, char *); + if (oif == NULL) + retval = LibAliasIn(t->lib, c, + MCLBYTES); + else + retval = LibAliasOut(t->lib, c, + MCLBYTES); + if (retval != PKT_ALIAS_OK) { + /* XXX - should i add some logging? */ + m_free(mcl); + badnat: + args->m = NULL; + retval = IP_FW_DENY; + goto done; + } + mcl->m_pkthdr.len = mcl->m_len = + ntohs(ip->ip_len); + + /* + * XXX - libalias checksum offload + * 'duct tape' (see above) + */ + + if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && + ip->ip_p == IPPROTO_TCP) { + struct tcphdr *th; + + th = (struct tcphdr *)(ip + 1); + if (th->th_x2) + ldt = 1; + } + + if (ldt) { + struct tcphdr *th; + struct udphdr *uh; + u_short cksum; + + ip->ip_len = ntohs(ip->ip_len); + cksum = in_pseudo( + ip->ip_src.s_addr, + ip->ip_dst.s_addr, + htons(ip->ip_p + ip->ip_len - + (ip->ip_hl << 2)) + ); + + switch (ip->ip_p) { + case IPPROTO_TCP: + th = (struct tcphdr *)(ip + 1); + /* + * Maybe it was set in + * libalias... + */ + th->th_x2 = 0; + th->th_sum = cksum; + mcl->m_pkthdr.csum_data = + offsetof(struct tcphdr, + th_sum); + break; + case IPPROTO_UDP: + uh = (struct udphdr *)(ip + 1); + uh->uh_sum = cksum; + mcl->m_pkthdr.csum_data = + offsetof(struct udphdr, + uh_sum); + break; + } + /* + * No hw checksum offloading: do it + * by ourself. + */ + if ((mcl->m_pkthdr.csum_flags & + CSUM_DELAY_DATA) == 0) { + in_delayed_cksum(mcl); + mcl->m_pkthdr.csum_flags &= + ~CSUM_DELAY_DATA; + } + ip->ip_len = htons(ip->ip_len); + } + + if (args->eh == NULL) { + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + } + + args->m = mcl; + retval = IP_FW_NAT; + goto done; + } + default: panic("-- unknown opcode %d\n", cmd->opcode); } /* end of switch() on opcodes */ @@ -3826,6 +4177,10 @@ check_ipfw_struct(struct ip_fw *rule, int size) return EINVAL; else goto check_size; + case O_NAT: + if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) + goto bad_size; + goto check_action; case O_FORWARD_MAC: /* XXX not implemented yet */ case O_CHECK_STATE: case O_COUNT: @@ -4201,6 +4556,185 @@ ipfw_ctl(struct sockopt *sopt) } break; + case IP_FW_NAT_CFG: + { + struct cfg_nat *ptr, *ser_n; + char *buf; + + buf = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO); + error = sooptcopyin(sopt, buf, NAT_BUF_LEN, + sizeof(struct cfg_nat)); + ser_n = (struct cfg_nat *)buf; + + /* + * Find/create nat rule. + */ + IPFW_WLOCK(&layer3_chain); + ptr = lookup_nat(ser_n->id); + if (ptr == NULL) { + /* New rule: allocate and init new instance. */ + ptr = malloc(sizeof(struct cfg_nat), + M_IPFW, M_NOWAIT | M_ZERO); + if (ptr == NULL) { + IPFW_WUNLOCK(&layer3_chain); + free(buf, M_IPFW); + return (ENOSPC); + } + ptr->lib = LibAliasInit(NULL); + if (ptr->lib == NULL) { + IPFW_WUNLOCK(&layer3_chain); + free(ptr, M_IPFW); + free(buf, M_IPFW); + return (EINVAL); + } + LIST_INIT(&ptr->redir_chain); + } else { + /* Entry already present: temporarly unhook it. */ + UNHOOK_NAT(ptr); + flush_nat_ptrs(ser_n->id); + } + IPFW_WUNLOCK(&layer3_chain); + + /* + * Basic nat configuration. + */ + ptr->id = ser_n->id; + /* + * XXX - what if this rule doesn't nat any ip and just + * redirect? + * do we set aliasaddress to 0.0.0.0? + */ + ptr->ip = ser_n->ip; + ptr->redir_cnt = ser_n->redir_cnt; + ptr->mode = ser_n->mode; + LibAliasSetMode(ptr->lib, ser_n->mode, ser_n->mode); + LibAliasSetAddress(ptr->lib, ptr->ip); + memcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE); + + /* + * Redir and LSNAT configuration. + */ + /* Delete old cfgs. */ + del_redir_spool_cfg(ptr, &ptr->redir_chain); + /* Add new entries. */ + add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr); + free(buf, M_IPFW); + IPFW_WLOCK(&layer3_chain); + HOOK_NAT(&layer3_chain.nat, ptr); + IPFW_WUNLOCK(&layer3_chain); + } + break; + + case IP_FW_NAT_DEL: + { + struct cfg_nat *ptr; + int i; + + error = sooptcopyin(sopt, &i, sizeof i, sizeof i); + IPFW_WLOCK(&layer3_chain); + ptr = lookup_nat(i); + if (ptr == NULL) { + error = EINVAL; + IPFW_WUNLOCK(&layer3_chain); + break; + } + UNHOOK_NAT(ptr); + flush_nat_ptrs(i); + IPFW_WUNLOCK(&layer3_chain); + del_redir_spool_cfg(ptr, &ptr->redir_chain); + LibAliasUninit(ptr->lib); + free(ptr, M_IPFW); + } + break; + + case IP_FW_NAT_GET_CONFIG: + { + uint8_t *data; + struct cfg_nat *n; + struct cfg_redir *r; + struct cfg_spool *s; + int nat_cnt, off; + + nat_cnt = 0; + off = sizeof(nat_cnt); + + data = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO); + IPFW_RLOCK(&layer3_chain); + /* Serialize all the data. */ + LIST_FOREACH(n, &layer3_chain.nat, _next) { + nat_cnt++; + if (off + SOF_NAT < NAT_BUF_LEN) { + bcopy(n, &data[off], SOF_NAT); + off += SOF_NAT; + LIST_FOREACH(r, &n->redir_chain, _next) { + if (off + SOF_REDIR < NAT_BUF_LEN) { + bcopy(r, &data[off], + SOF_REDIR); + off += SOF_REDIR; + LIST_FOREACH(s, &r->spool_chain, + _next) { + if (off + SOF_SPOOL < + NAT_BUF_LEN) { + bcopy(s, + &data[off], + SOF_SPOOL); + off += + SOF_SPOOL; + } else + goto nospace; + } + } else + goto nospace; + } + } else + goto nospace; + } + bcopy(&nat_cnt, data, sizeof(nat_cnt)); + IPFW_RUNLOCK(&layer3_chain); + error = sooptcopyout(sopt, data, NAT_BUF_LEN); + free(data, M_IPFW); + break; + nospace: + IPFW_RUNLOCK(&layer3_chain); + printf("serialized data buffer not big enough:" + "please increase NAT_BUF_LEN\n"); + free(data, M_IPFW); + } + break; + + case IP_FW_NAT_GET_LOG: + { + uint8_t *data; + struct cfg_nat *ptr; + int i, size, cnt, sof; + + data = NULL; + sof = LIBALIAS_BUF_SIZE; + cnt = 0; + + IPFW_RLOCK(&layer3_chain); + size = i = 0; + LIST_FOREACH(ptr, &layer3_chain.nat, _next) { + if (ptr->lib->logDesc == NULL) + continue; + cnt++; + size = cnt * (sof + sizeof(int)); + data = realloc(data, size, M_IPFW, M_NOWAIT | M_ZERO); + if (data == NULL) { + IPFW_RUNLOCK(&layer3_chain); + return (ENOSPC); + } + bcopy(&ptr->id, &data[i], sizeof(int)); + i += sizeof(int); + bcopy(ptr->lib->logDesc, &data[i], sof); + i += sof; + } + IPFW_RUNLOCK(&layer3_chain); + error = sooptcopyout(sopt, data, size); + free(data, M_IPFW); + } + break; + default: printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); error = EINVAL; @@ -4372,8 +4906,10 @@ ipfw_init(void) } ip_fw_ctl_ptr = ipfw_ctl; ip_fw_chk_ptr = ipfw_chk; - callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL); - + callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL); + LIST_INIT(&layer3_chain.nat); + ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change, + NULL, EVENTHANDLER_PRI_ANY); return (0); } @@ -4381,12 +4917,20 @@ void ipfw_destroy(void) { struct ip_fw *reap; + struct cfg_nat *ptr, *ptr_temp; ip_fw_chk_ptr = NULL; ip_fw_ctl_ptr = NULL; callout_drain(&ipfw_timeout); IPFW_WLOCK(&layer3_chain); flush_tables(&layer3_chain); + LIST_FOREACH_SAFE(ptr, &layer3_chain.nat, _next, ptr_temp) { + LIST_REMOVE(ptr, _next); + del_redir_spool_cfg(ptr, &ptr->redir_chain); + LibAliasUninit(ptr->lib); + free(ptr, M_IPFW); + } + EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag); layer3_chain.reap = NULL; free_chain(&layer3_chain, 1 /* kill default rule */); reap = layer3_chain.reap, layer3_chain.reap = NULL; diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c index a58f96f..d8285b5 100644 --- a/sys/netinet/ip_fw_pfil.c +++ b/sys/netinet/ip_fw_pfil.c @@ -189,6 +189,9 @@ again: if (!NG_IPFW_LOADED) goto drop; return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0); + + case IP_FW_NAT: + goto again; /* continue with packet */ default: KASSERT(0, ("%s: unknown retval", __func__)); @@ -315,6 +318,9 @@ again: goto drop; return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0); + case IP_FW_NAT: + goto again; /* continue with packet */ + default: KASSERT(0, ("%s: unknown retval", __func__)); } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index c6900b2..51fe333 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -389,6 +389,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_GET: case IP_FW_TABLE_GETSIZE: case IP_FW_TABLE_LIST: + case IP_FW_NAT_GET_CONFIG: + case IP_FW_NAT_GET_LOG: /* * XXXRW: Isn't this checked one layer down? Yes, it * is. @@ -458,6 +460,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_TABLE_ADD: case IP_FW_TABLE_DEL: case IP_FW_TABLE_FLUSH: + case IP_FW_NAT_CFG: + case IP_FW_NAT_DEL: /* * XXXRW: Isn't this checked one layer down? */ |