You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by "wengzhe (via GitHub)" <gi...@apache.org> on 2024/06/17 03:26:44 UTC
[PR] net: Support packet filter (firewall) and corresponding iptables/ip6tables [nuttx]
wengzhe opened a new pull request, #12508:
URL: https://github.com/apache/nuttx/pull/12508
## Summary
Patches included:
- net: Support IP packet filter
- net/netfilter: Add filter table in iptables.
- net: Add set/getsockopt options compatible with ip6tables
- net/netfilter: Add filter table in ip6tables
- net/netfilter: Rename TABLE_NAME_NAT to XT_TABLE_NAME_NAT
- Documentation: Add docs for ipfilter
Add a firewall compatible with Linux's iptables and ip6tables, with chains at similar points in the packet processing path. More details and examples are in the doc.
```
NIC ──> ipv[46]_input ─┬─> ipv[46]_forward ──> [FORWARD CHAIN] ──> devif_poll_out ──> NIC
│ ^
│ ┌─> tcp ─┐ │
│ ├─> udp ─┤ │
└─> [INPUT CHAIN] ─┼─> icmp ─┼─> [OUTPUT CHAIN] ─┘
├─> icmp6 ─┤
└─> ... ─┘
```
## Impact
Changes limited in `net/ipfilter`(firewall) `net/netfilter` (interface) and minimum other modules, all controlled by `CONFIG_NET_IPFILTER`
## Testing
Together with <>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] net: Support packet filter (firewall) and corresponding iptables/ip6tables [nuttx]
Posted by "anchao (via GitHub)" <gi...@apache.org>.
anchao commented on code in PR #12508:
URL: https://github.com/apache/nuttx/pull/12508#discussion_r1644136648
##########
net/devif/devif_poll.c:
##########
@@ -184,6 +185,32 @@ static void devif_packet_conversion(FAR struct net_driver_s *dev,
# define devif_packet_conversion(dev,pkttype)
#endif /* CONFIG_NET_6LOWPAN */
+/****************************************************************************
+ * Name: devif_poll_local_out
+ *
+ * Description:
+ * Generic callback before device output to build L2 headers before sending
+ * with packet filter for TCP/UDP/ICMP(v6).
+ *
+ * Assumptions:
+ * This function is called from the MAC device driver with the network
+ * locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPFILTER
+static int devif_poll_local_out(FAR struct net_driver_s *dev,
+ devif_poll_callback_t callback)
+{
+ /* Maybe we need to reply REJECT to ourself, so filter before loopback. */
+
+ ipfilter_out(dev);
Review Comment:
```suggestion
#ifdef CONFIG_NET_IPFILTER
ipfilter_out(dev);
#endif /* CONFIG_NET_IPFILTER */
```
##########
net/ipfilter/ipfilter.c:
##########
@@ -0,0 +1,632 @@
+/****************************************************************************
+ * net/ipfilter/ipfilter.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/icmpv6.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/udp.h>
+#include <nuttx/queue.h>
+
+#include "icmp/icmp.h"
+#include "icmpv6/icmpv6.h"
+#include "ipfilter/ipfilter.h"
+#include "utils/utils.h"
+
+#ifdef CONFIG_NET_IPFILTER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SPORT_MATCH(entry, sport) \
+ (((sport) >= (entry)->match.tcpudp.sports[0] && \
+ (sport) <= (entry)->match.tcpudp.sports[1]) ^ (entry)->inv_sport)
+
+#define DPORT_MATCH(entry, dport) \
+ (((dport) >= (entry)->match.tcpudp.dports[0] && \
+ (dport) <= (entry)->match.tcpudp.dports[1]) ^ (entry)->inv_dport)
+
+#define ICMP_MATCH(entry, icmphdr) \
+ (((entry)->match.icmp.type == 0xFF || \
+ (entry)->match.icmp.type == (icmphdr)->type) ^ (entry)->inv_icmp)
+
+/* Getting L4 header from IPv4/IPv6 header. */
+
+#define IPv4_L4HDR(ipv4) \
+ ((FAR void *)((FAR uint8_t *)(ipv4) + (((ipv4)->vhl & IPv4_HLMASK) << 2)))
+
+#define IPv6_L4HDR(ipv6, proto) \
+ ((FAR void *)(net_ipv6_payload((FAR struct ipv6_hdr_s *)(ipv6), &(proto))))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static sq_queue_t g_ipv4_filters[IPFILTER_CHAIN_MAX];
+#endif
+#ifdef CONFIG_NET_IPv6
+static sq_queue_t g_ipv6_filters[IPFILTER_CHAIN_MAX];
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipfilter_match_device
+ *
+ * Description:
+ * Match the packet with the filter entries on devices.
+ *
+ * Input Parameters:
+ * entry - The filter entry to match
+ * indev - The network device that the packet comes from
+ * outdev - The network device that the packet goes to
+ *
+ * Returned Value:
+ * true - The input packet is matched
+ * false - The input packet is not matched
+ *
+ ****************************************************************************/
+
+static bool ipfilter_match_device(FAR const struct ipfilter_entry_s *entry,
+ FAR const struct net_driver_s *indev,
+ FAR const struct net_driver_s *outdev)
+{
+ bool matched;
+
+ if (indev != NULL && entry->indev != NULL)
+ {
+ matched = (indev == entry->indev) ^ entry->inv_indev;
+ if (!matched)
+ {
+ return false;
+ }
+ }
+
+ if (outdev != NULL && entry->outdev != NULL)
+ {
+ matched = (outdev == entry->outdev) ^ entry->inv_outdev;
+ if (!matched)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ * Name: ipfilter_match_proto
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static bool ipfilter_match_proto(FAR const struct ipfilter_entry_s *entry,
+ FAR const void *l4hdr, uint8_t proto)
+{
+ bool matched;
+
+ if (entry->proto)
+ {
+ matched = (entry->proto == proto) ^ entry->inv_proto;
+ if (!matched)
+ {
+ return false;
+ }
+ }
+
+ if (entry->inv_proto)
+ {
+ /* Cannot match port/type for inversed proto, just success. */
+
+ return true;
+ }
+
+ switch (proto)
+ {
+ case IP_PROTO_TCP:
+ case IP_PROTO_UDP:
+ if (entry->match_tcpudp)
+ {
+ /* Ports in TCP & UDP headers have same offset. */
+
+ FAR const struct udp_hdr_s *udp = l4hdr;
+ return SPORT_MATCH(entry, NTOHS(udp->srcport)) &&
+ DPORT_MATCH(entry, NTOHS(udp->destport));
+ }
+
+ case IP_PROTO_ICMP:
+ if (entry->match_icmp)
+ {
+ FAR const struct icmp_hdr_s *icmp = l4hdr;
+ return ICMP_MATCH(entry, icmp);
+ }
+
+ case IP_PROTO_ICMP6:
+ if (entry->match_icmp)
+ {
+ FAR const struct icmpv6_hdr_s *icmpv6 = l4hdr;
+ return ICMP_MATCH(entry, icmpv6);
+ }
+
+ default:
+ return true;
+ }
+}
+
+/****************************************************************************
+ * Name: ipv4_filter_match / ipv6_filter_match
+ *
+ * Description:
+ * Match the input packet with the filter entries in the specified chain.
+ *
+ * Input Parameters:
+ * indev - The network device that the packet comes from
+ * outdev - The network device that the packet goes to
+ * ipv4/ipv6 - The IPv4/IPv6 header
+ * chain - The chain to match the filter entries
+ *
+ * Returned Value:
+ * IPFILTER_TARGET_ACCEPT(0) - The input packet is accepted
+ * IPFILTER_TARGET_DROP(-1) - The input packet needs to be dropped
+ * IPFILTER_TARGET_REJECT(-2) - The input packet is rejected
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static int ipv4_filter_match(FAR const struct net_driver_s *indev,
+ FAR const struct net_driver_s *outdev,
+ FAR const struct ipv4_hdr_s *ipv4,
+ enum ipfilter_chain_e chain)
+{
+ FAR const struct ipv4_filter_entry_s *filter;
+ FAR const sq_queue_t *queue = &g_ipv4_filters[chain];
+ FAR const sq_entry_t *entry;
+ FAR const void *l4hdr;
+ in_addr_t ipaddr;
+ bool matched;
+
+ /* Handle unexpected status, return ACCEPT to indicate doing nothing. */
+
+ if ((indev == NULL && outdev == NULL) || ipv4 == NULL)
+ {
+ return IPFILTER_TARGET_ACCEPT;
+ }
+
+ l4hdr = IPv4_L4HDR(ipv4);
+
+ sq_for_every(queue, entry)
+ {
+ filter = (FAR struct ipv4_filter_entry_s *)entry;
+
+ /* Match device */
+
+ if (!ipfilter_match_device(&filter->common, indev, outdev))
+ {
+ continue;
+ }
+
+ /* Match addresses */
+
+ ipaddr = net_ip4addr_conv32(ipv4->srcipaddr);
+ matched = net_ipv4addr_maskcmp(filter->sip, ipaddr, filter->smsk)
+ ^ filter->common.inv_srcip;
+ if (!matched)
+ {
+ continue;
+ }
+
+ ipaddr = net_ip4addr_conv32(ipv4->destipaddr);
+ matched = net_ipv4addr_maskcmp(filter->dip, ipaddr, filter->dmsk)
+ ^ filter->common.inv_dstip;
+ if (!matched)
+ {
+ continue;
+ }
+
+ /* Match protocol */
+
+ if (!ipfilter_match_proto(&filter->common, l4hdr, ipv4->proto))
+ {
+ continue;
+ }
+
+ /* Return the target action if matched. */
+
+ return filter->common.target;
+ }
+
+ /* Normally there should be a default rule in chain, won't reach here. */
+
+ ninfo("No filter matched, maybe uninitialized.\n");
+ return IPFILTER_TARGET_ACCEPT;
+}
+#endif
+
+#ifdef CONFIG_NET_IPv6
+static int ipv6_filter_match(FAR const struct net_driver_s *indev,
+ FAR const struct net_driver_s *outdev,
+ FAR const struct ipv6_hdr_s *ipv6,
+ enum ipfilter_chain_e chain)
+{
+ FAR const struct ipv6_filter_entry_s *filter;
+ FAR const sq_queue_t *queue = &g_ipv6_filters[chain];
+ FAR const sq_entry_t *entry;
+ FAR const void *l4hdr;
+ uint8_t proto;
+ bool matched;
+
+ /* Handle unexpected status, return ACCEPT to indicate doing nothing. */
+
+ if ((indev == NULL && outdev == NULL) || ipv6 == NULL)
+ {
+ return IPFILTER_TARGET_ACCEPT;
+ }
+
+ l4hdr = IPv6_L4HDR(ipv6, proto);
+
+ sq_for_every(queue, entry)
+ {
+ filter = (FAR struct ipv6_filter_entry_s *)entry;
+
+ /* Match device */
+
+ if (!ipfilter_match_device(&filter->common, indev, outdev))
+ {
+ continue;
+ }
+
+ /* Match addresses */
+
+ matched = net_ipv6addr_maskcmp(filter->sip, ipv6->srcipaddr,
+ filter->smsk)
+ ^ filter->common.inv_srcip;
+ if (!matched)
+ {
+ continue;
+ }
+
+ matched = net_ipv6addr_maskcmp(filter->dip, ipv6->destipaddr,
+ filter->dmsk)
+ ^ filter->common.inv_dstip;
+ if (!matched)
+ {
+ continue;
+ }
+
+ /* Match protocol */
+
+ if (!ipfilter_match_proto(&filter->common, l4hdr, proto))
+ {
+ continue;
+ }
+
+ /* Return the target action if matched. */
+
+ return filter->common.target;
+ }
+
+ /* Normally there should be a default rule in chain, won't reach here. */
+
+ ninfo("No filter matched, maybe uninitialized.\n");
+ return IPFILTER_TARGET_ACCEPT;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipfilter_cfg_alloc
+ *
+ * Description:
+ * Allocate a new filter configuration entry for the given address family.
+ *
+ * Input Parameters:
+ * family - The address family of the filter entry
+ *
+ * Returned Value:
+ * A pointer to the newly allocated filter entry. NULL is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+FAR struct ipfilter_entry_s *ipfilter_cfg_alloc(sa_family_t family)
Review Comment:
remove this method if nobody using
##########
net/netfilter/ipt_filter.c:
##########
@@ -0,0 +1,593 @@
+/****************************************************************************
+ * net/netfilter/ipt_filter.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/netfilter/ip_tables.h>
+#include <nuttx/net/netfilter/x_tables.h>
+
+#include "ipfilter/ipfilter.h"
+#include "netdev/netdev.h"
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT))
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: convert_chain
+ *
+ * Description:
+ * Convert iptables chain to ipfilter chain.
+ *
+ ****************************************************************************/
+
+static enum ipfilter_chain_e convert_chain(enum nf_inet_hooks hook)
+{
+ switch (hook)
+ {
+ case NF_INET_LOCAL_IN:
+ return IPFILTER_CHAIN_INPUT;
+
+ case NF_INET_FORWARD:
+ return IPFILTER_CHAIN_FORWARD;
+
+ case NF_INET_LOCAL_OUT:
+ default:
+ return IPFILTER_CHAIN_OUTPUT;
+ }
+}
+
+/****************************************************************************
+ * Name: convert_invflags
+ *
+ * Description:
+ * Convert iptables invflags to ipfilter invflags.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * invflags - The iptables invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_invflags(FAR struct ipfilter_entry_s *entry,
+ uint8_t invflags)
+{
+ entry->inv_indev = !!(invflags & IPT_INV_VIA_IN);
+ entry->inv_outdev = !!(invflags & IPT_INV_VIA_OUT);
+ entry->inv_proto = !!(invflags & IPT_INV_PROTO);
+ entry->inv_srcip = !!(invflags & IPT_INV_SRCIP);
+ entry->inv_dstip = !!(invflags & IPT_INV_DSTIP);
+}
+
+/****************************************************************************
+ * Name: convert_tcpudp
+ *
+ * Description:
+ * Convert iptables tcp/udp match to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * spts - The source ports to be converted.
+ * dpts - The destination ports to be converted.
+ * invflags - The iptables tcp/udp invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_tcpudp(FAR struct ipfilter_entry_s *entry,
+ uint16_t spts[2], uint16_t dpts[2],
+ uint8_t invflags)
+{
+ entry->match.tcpudp.sports[0] = spts[0];
+ entry->match.tcpudp.sports[1] = spts[1];
+ entry->match.tcpudp.dports[0] = dpts[0];
+ entry->match.tcpudp.dports[1] = dpts[1];
+
+ entry->inv_sport = !!(invflags & XT_TCP_INV_SRCPT);
+ entry->inv_dport = !!(invflags & XT_TCP_INV_DSTPT);
+
+ entry->match_tcpudp = 1;
+}
+
+/****************************************************************************
+ * Name: convert_icmp
+ *
+ * Description:
+ * Convert iptables icmp match to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * type - The icmp type to be converted.
+ * invflags - The iptables icmp invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_icmp(FAR struct ipfilter_entry_s *entry, uint8_t type,
+ uint8_t invflags)
+{
+ entry->match.icmp.type = type;
+ entry->inv_icmp = !!(invflags & IPT_ICMP_INV);
+ entry->match_icmp = 1;
+}
+
+/****************************************************************************
+ * Name: convert_target
+ *
+ * Description:
+ * Convert iptables target to ipfilter target.
+ *
+ * Input Parameters:
+ * target - The iptables target to be converted.
+ *
+ * Returned Value:
+ * The converted ipfilter target.
+ *
+ ****************************************************************************/
+
+static uint8_t convert_target(FAR const struct xt_entry_target *target)
+{
+ if (strcmp(target->u.user.name, XT_REJECT_TARGET) == 0)
+ {
+ return IPFILTER_TARGET_REJECT;
+ }
+
+ if (strcmp(target->u.user.name, XT_STANDARD_TARGET) == 0)
+ {
+ int verdict = ((FAR const struct xt_standard_target *)target)->verdict;
+ verdict = -verdict - 1;
+
+ if (verdict == NF_ACCEPT)
+ {
+ return IPFILTER_TARGET_ACCEPT;
+ }
+ else if (verdict == NF_DROP)
+ {
+ return IPFILTER_TARGET_DROP;
+ }
+ }
+
+ nwarn("WARNING: Unsupported target %s\n", target->u.user.name);
+ return IPFILTER_TARGET_DROP;
+}
+
+/****************************************************************************
+ * Name: convert_entry
+ *
+ * Description:
+ * Convert iptables entry to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The iptables entry to be converted.
+ *
+ * Returned Value:
+ * The converted ipfilter entry.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static FAR struct ipv4_filter_entry_s *
+convert_ipv4entry(FAR const struct ipt_entry *entry)
+{
+ FAR const struct xt_entry_match *match;
+ FAR const struct xt_entry_target *target;
+ FAR struct ipv4_filter_entry_s *filter;
+
+ filter = kmm_zalloc(sizeof(struct ipv4_filter_entry_s));
+
+ match = IPT_MATCH(entry);
+ target = IPT_TARGET(entry);
+
+ /* Convert common fields */
+
+ filter->sip = entry->ip.src.s_addr;
+ filter->dip = entry->ip.dst.s_addr;
+ filter->smsk = entry->ip.smsk.s_addr;
+ filter->dmsk = entry->ip.dmsk.s_addr;
+
+ filter->common.indev = netdev_findbyname(entry->ip.iniface);
+ filter->common.outdev = netdev_findbyname(entry->ip.outiface);
+ filter->common.proto = entry->ip.proto;
+ filter->common.target = convert_target(target);
+
+ convert_invflags(&filter->common, entry->ip.invflags);
+
+ /* Convert match fields */
+
+ if (entry->target_offset < sizeof(struct xt_entry_match))
+ {
+ ninfo("No match inside entry, skip match conversion.\n");
+ goto skip_match;
+ }
+
+ switch (entry->ip.proto)
+ {
+ case IPPROTO_TCP:
+ if (strcmp(match->u.user.name, XT_MATCH_NAME_TCP) == 0)
+ {
+ FAR struct xt_tcp *tcp = (FAR struct xt_tcp *)(match + 1);
+ convert_tcpudp(&filter->common, tcp->spts, tcp->dpts,
+ tcp->invflags);
+ }
+ break;
+
+ case IPPROTO_UDP:
+ if (strcmp(match->u.user.name, XT_MATCH_NAME_TCP) == 0)
+ {
+ FAR struct xt_udp *udp = (FAR struct xt_udp *)(match + 1);
+ convert_tcpudp(&filter->common, udp->spts, udp->dpts,
+ udp->invflags);
+ }
+ break;
+
+ case IPPROTO_ICMP:
+ if (strcmp(match->u.user.name, XT_MATCH_NAME_ICMP) == 0)
+ {
+ FAR struct ipt_icmp *icmp = (FAR struct ipt_icmp *)(match + 1);
+ convert_icmp(&filter->common, icmp->type, icmp->invflags);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+skip_match:
+ return filter;
+}
+#endif
+
+#ifdef CONFIG_NET_IPv6
+static FAR struct ipv6_filter_entry_s *
+convert_ipv6entry(FAR const struct ip6t_entry *entry)
+{
+ FAR const struct xt_entry_match *match;
+ FAR const struct xt_entry_target *target;
+ FAR struct ipv6_filter_entry_s *filter;
+
+ filter = kmm_zalloc(sizeof(struct ipv6_filter_entry_s));
Review Comment:
ditto
##########
net/netfilter/ipt_filter.c:
##########
@@ -0,0 +1,593 @@
+/****************************************************************************
+ * net/netfilter/ipt_filter.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/netfilter/ip_tables.h>
+#include <nuttx/net/netfilter/x_tables.h>
+
+#include "ipfilter/ipfilter.h"
+#include "netdev/netdev.h"
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT))
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: convert_chain
+ *
+ * Description:
+ * Convert iptables chain to ipfilter chain.
+ *
+ ****************************************************************************/
+
+static enum ipfilter_chain_e convert_chain(enum nf_inet_hooks hook)
+{
+ switch (hook)
+ {
+ case NF_INET_LOCAL_IN:
+ return IPFILTER_CHAIN_INPUT;
+
+ case NF_INET_FORWARD:
+ return IPFILTER_CHAIN_FORWARD;
+
+ case NF_INET_LOCAL_OUT:
+ default:
+ return IPFILTER_CHAIN_OUTPUT;
+ }
+}
+
+/****************************************************************************
+ * Name: convert_invflags
+ *
+ * Description:
+ * Convert iptables invflags to ipfilter invflags.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * invflags - The iptables invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_invflags(FAR struct ipfilter_entry_s *entry,
+ uint8_t invflags)
+{
+ entry->inv_indev = !!(invflags & IPT_INV_VIA_IN);
+ entry->inv_outdev = !!(invflags & IPT_INV_VIA_OUT);
+ entry->inv_proto = !!(invflags & IPT_INV_PROTO);
+ entry->inv_srcip = !!(invflags & IPT_INV_SRCIP);
+ entry->inv_dstip = !!(invflags & IPT_INV_DSTIP);
+}
+
+/****************************************************************************
+ * Name: convert_tcpudp
+ *
+ * Description:
+ * Convert iptables tcp/udp match to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * spts - The source ports to be converted.
+ * dpts - The destination ports to be converted.
+ * invflags - The iptables tcp/udp invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_tcpudp(FAR struct ipfilter_entry_s *entry,
+ uint16_t spts[2], uint16_t dpts[2],
+ uint8_t invflags)
+{
+ entry->match.tcpudp.sports[0] = spts[0];
+ entry->match.tcpudp.sports[1] = spts[1];
+ entry->match.tcpudp.dports[0] = dpts[0];
+ entry->match.tcpudp.dports[1] = dpts[1];
+
+ entry->inv_sport = !!(invflags & XT_TCP_INV_SRCPT);
+ entry->inv_dport = !!(invflags & XT_TCP_INV_DSTPT);
+
+ entry->match_tcpudp = 1;
+}
+
+/****************************************************************************
+ * Name: convert_icmp
+ *
+ * Description:
+ * Convert iptables icmp match to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The ipfilter entry to be filled.
+ * type - The icmp type to be converted.
+ * invflags - The iptables icmp invflags to be converted.
+ *
+ ****************************************************************************/
+
+static void convert_icmp(FAR struct ipfilter_entry_s *entry, uint8_t type,
+ uint8_t invflags)
+{
+ entry->match.icmp.type = type;
+ entry->inv_icmp = !!(invflags & IPT_ICMP_INV);
+ entry->match_icmp = 1;
+}
+
+/****************************************************************************
+ * Name: convert_target
+ *
+ * Description:
+ * Convert iptables target to ipfilter target.
+ *
+ * Input Parameters:
+ * target - The iptables target to be converted.
+ *
+ * Returned Value:
+ * The converted ipfilter target.
+ *
+ ****************************************************************************/
+
+static uint8_t convert_target(FAR const struct xt_entry_target *target)
+{
+ if (strcmp(target->u.user.name, XT_REJECT_TARGET) == 0)
+ {
+ return IPFILTER_TARGET_REJECT;
+ }
+
+ if (strcmp(target->u.user.name, XT_STANDARD_TARGET) == 0)
+ {
+ int verdict = ((FAR const struct xt_standard_target *)target)->verdict;
+ verdict = -verdict - 1;
+
+ if (verdict == NF_ACCEPT)
+ {
+ return IPFILTER_TARGET_ACCEPT;
+ }
+ else if (verdict == NF_DROP)
+ {
+ return IPFILTER_TARGET_DROP;
+ }
+ }
+
+ nwarn("WARNING: Unsupported target %s\n", target->u.user.name);
+ return IPFILTER_TARGET_DROP;
+}
+
+/****************************************************************************
+ * Name: convert_entry
+ *
+ * Description:
+ * Convert iptables entry to ipfilter entry.
+ *
+ * Input Parameters:
+ * entry - The iptables entry to be converted.
+ *
+ * Returned Value:
+ * The converted ipfilter entry.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static FAR struct ipv4_filter_entry_s *
+convert_ipv4entry(FAR const struct ipt_entry *entry)
+{
+ FAR const struct xt_entry_match *match;
+ FAR const struct xt_entry_target *target;
+ FAR struct ipv4_filter_entry_s *filter;
+
+ filter = kmm_zalloc(sizeof(struct ipv4_filter_entry_s));
Review Comment:
add sanity check for `filter == NULL`
##########
net/netfilter/ip6t_sockopt.c:
##########
@@ -0,0 +1,444 @@
+/****************************************************************************
+ * net/netfilter/ip6t_sockopt.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <sys/param.h>
+
+#include <nuttx/kmalloc.h>
+
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SWAP(a,b,t) do { (t) = (a); (a) = (b); (b) = (t); } while (0)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Structure to store all info we need, including table data and
+ * init/apply functions.
+ */
+
+struct ip6t_table_s
+{
+ FAR struct ip6t_replace *repl;
+ FAR struct ip6t_replace *(*init_func)(void);
+ FAR int (*apply_func)(FAR const struct ip6t_replace *);
+};
+
+/* Following structs represent the layout of an entry with standard/error
+ * target (without matches). Mainly used to simplify initialization (entry
+ * creation), not suggested to use under other situations, because there
+ * might be matches between entry and target in data from user space.
+ */
+
+struct ip6t_standard_entry_s
+{
+ struct ip6t_entry entry;
+ struct xt_standard_target target;
+};
+
+struct ip6t_error_entry_s
+{
+ struct ip6t_entry entry;
+ struct xt_error_target target;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct ip6t_table_s g_tables[] =
+{
+#ifdef CONFIG_NET_IPFILTER
+ {NULL, ip6t_filter_init, ip6t_filter_apply},
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ip6t_table_init
+ *
+ * Description:
+ * Try initialize the table data if not initialized.
+ *
+ ****************************************************************************/
+
+static void ip6t_table_init(FAR struct ip6t_table_s *table)
+{
+ if (table->repl == NULL && table->init_func != NULL)
+ {
+ table->repl = table->init_func();
+ }
+}
+
+/****************************************************************************
+ * Name: ip6t_table
+ *
+ * Description:
+ * Find table data by table name.
+ *
+ ****************************************************************************/
+
+static FAR struct ip6t_table_s *ip6t_table(FAR const char *name)
+{
+ int i;
+ for (i = 0; i < nitems(g_tables); i++)
+ {
+ ip6t_table_init(&g_tables[i]);
+ if (g_tables[i].repl != NULL &&
+ strcmp(g_tables[i].repl->name, name) == 0)
+ {
+ return &g_tables[i];
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: ip6t_table_repl
+ *
+ * Description:
+ * Find table data by table name.
+ *
+ ****************************************************************************/
+
+static FAR struct ip6t_replace *ip6t_table_repl(FAR const char *name)
+{
+ FAR struct ip6t_table_s *table = ip6t_table(name);
+ if (table)
+ {
+ return table->repl;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: get_info
+ *
+ * Description:
+ * Fill table info into ip6t_getinfo structure.
+ *
+ * Input Parameters:
+ * get, len - The parameters from getsockopt.
+ *
+ ****************************************************************************/
+
+static int get_info(FAR struct ip6t_getinfo *get, FAR socklen_t *len)
+{
+ FAR struct ip6t_replace *repl;
+
+ if (*len != sizeof(*get))
+ {
+ return -EINVAL;
+ }
+
+ repl = ip6t_table_repl(get->name);
+ if (repl == NULL)
+ {
+ return -ENOENT;
+ }
+
+ get->valid_hooks = repl->valid_hooks;
+ memcpy(get->hook_entry, repl->hook_entry, sizeof(get->hook_entry));
+ memcpy(get->underflow, repl->underflow, sizeof(get->underflow));
+ get->num_entries = repl->num_entries;
+ get->size = repl->size;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: get_entries
+ *
+ * Description:
+ * Fill entry info into ip6t_get_entries structure.
+ *
+ * Input Parameters:
+ * get, len - The parameters from getsockopt.
+ *
+ ****************************************************************************/
+
+static int get_entries(FAR struct ip6t_get_entries *get, FAR socklen_t *len)
+{
+ FAR struct ip6t_replace *repl;
+
+ if (*len < sizeof(*get) || *len != sizeof(*get) + get->size)
+ {
+ return -EINVAL;
+ }
+
+ repl = ip6t_table_repl(get->name);
+ if (repl == NULL)
+ {
+ return -ENOENT;
+ }
+
+ if (get->size != repl->size)
+ {
+ return -EAGAIN;
+ }
+
+ memcpy(get->entrytable, repl->entries, get->size);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: check_replace
+ *
+ * Description:
+ * Check whether an ip6t_replace structure from user space is valid.
+ *
+ * Input Parameters:
+ * repl - The ip6t_replace structure to check.
+ *
+ * Returned Value:
+ * OK if repl is valid, otherwise -EINVAL.
+ *
+ ****************************************************************************/
+
+static int check_replace(FAR const struct ip6t_replace *repl)
+{
+ FAR struct ip6t_entry *entry;
+ unsigned int entry_count = 0;
+
+ ip6t_entry_for_every(entry, repl->entries, repl->size)
+ {
+ entry_count++;
+ if (entry->next_offset == 0)
+ {
+ return -EINVAL;
+ }
+ }
+
+ if (entry_count != repl->num_entries)
+ {
+ return -EINVAL;
+ }
+
+ /* May add more checks later. */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: replace_entries
+ *
+ * Description:
+ * Apply replace data to kernel tables.
+ *
+ * Input Parameters:
+ * repl, len - The parameters from setsockopt.
+ *
+ ****************************************************************************/
+
+static int replace_entries(FAR const struct ip6t_replace *repl,
+ socklen_t len)
+{
+ int ret;
+ FAR struct ip6t_replace *new_repl;
+ FAR struct ip6t_table_s *table = ip6t_table(repl->name);
+
+ if (table == NULL || table->repl == NULL)
+ {
+ return -ENOENT;
+ }
+
+ if (len < sizeof(*repl) || len != sizeof(*repl) + repl->size ||
Review Comment:
```suggestion
if (len != sizeof(*repl) + repl->size ||
```
##########
net/netfilter/ip6t_sockopt.c:
##########
@@ -0,0 +1,444 @@
+/****************************************************************************
+ * net/netfilter/ip6t_sockopt.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <sys/param.h>
+
+#include <nuttx/kmalloc.h>
+
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SWAP(a,b,t) do { (t) = (a); (a) = (b); (b) = (t); } while (0)
Review Comment:
```suggestion
#define SWAP(a,b,t) do { FAR void *t; (t) = (a); (a) = (b); (b) = (t); } while (0)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org