diff --git a/include/netpacket/netlink.h b/include/netpacket/netlink.h index 2b443ac6a9..da4e13e165 100644 --- a/include/netpacket/netlink.h +++ b/include/netpacket/netlink.h @@ -437,6 +437,160 @@ #define RTM_F_CLONED 0x200 /* This route is cloned */ +/* Attribute definitions for struct nfattr **********************************/ + +/* Macros to handle attribute lists */ + +#define NFNL_NFA_NEST 0x8000 +#define NFA_TYPE(attr) ((attr)->nfa_type & 0x7fff) + +#define NFA_MASK (sizeof(uint32_t) - 1) +#define NFA_ALIGN(n) (((n) + NFA_MASK) & ~NFA_MASK) +#define NFA_OK(nfa, n) \ + ((n) >= (int)sizeof(struct nfattr) && \ + (nfa)->nfa_len >= sizeof(struct nfattr) && \ + (nfa)->nfa_len <= (n)) +#define NFA_NEXT(nfa, attrlen) \ + ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ + (FAR struct nfattr *)(((FAR char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) +#define NFA_LENGTH(len) ((sizeof(struct nfattr)) + (len)) +#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) +#define NFA_DATA(nfa) ((FAR void *)(((FAR char *)(nfa)) + NFA_LENGTH(0))) +#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) + +/* Definitions for struct nfgenmsg ******************************************/ + +#define NFM_NFA(n) ((FAR struct nfattr *) \ + (((FAR char *)(n)) + \ + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) +#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) + +/* Definitions for NETLINK_NETFILTER ****************************************/ + +#define NFNETLINK_V0 0 + +/* netfilter netlink message types are split in two pieces: + * 8 bit subsystem, 8bit operation. + */ + +#define NFNL_SUBSYS_ID(x) (((x) & 0xff00) >> 8) +#define NFNL_MSG_TYPE(x) ((x) & 0x00ff) + +/* subsystems */ + +#define NFNL_SUBSYS_NONE 0 +#define NFNL_SUBSYS_CTNETLINK 1 +#define NFNL_SUBSYS_CTNETLINK_EXP 2 +#define NFNL_SUBSYS_QUEUE 3 +#define NFNL_SUBSYS_ULOG 4 +#define NFNL_SUBSYS_OSF 5 +#define NFNL_SUBSYS_IPSET 6 +#define NFNL_SUBSYS_ACCT 7 +#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 +#define NFNL_SUBSYS_CTHELPER 9 +#define NFNL_SUBSYS_NFTABLES 10 +#define NFNL_SUBSYS_NFT_COMPAT 11 +#define NFNL_SUBSYS_HOOK 12 +#define NFNL_SUBSYS_COUNT 13 + +/* NETLINK_NETFILTER: subsystem CTNL (ip conntrack netlink) message types */ + +#define IPCTNL_MSG_CT_NEW 0 +#define IPCTNL_MSG_CT_GET 1 +#define IPCTNL_MSG_CT_DELETE 2 +#define IPCTNL_MSG_CT_GET_CTRZERO 3 +#define IPCTNL_MSG_CT_GET_STATS_CPU 4 +#define IPCTNL_MSG_CT_GET_STATS 5 +#define IPCTNL_MSG_CT_GET_DYING 6 +#define IPCTNL_MSG_CT_GET_UNCONFIRMED 7 +#define IPCTNL_MSG_MAX 8 + +/* NETLINK_NETFILTER: Conntrack attributes */ + +#define CTA_UNSPEC 0 +#define CTA_TUPLE_ORIG 1 +#define CTA_TUPLE_REPLY 2 +#define CTA_STATUS 3 +#define CTA_PROTOINFO 4 +#define CTA_HELP 5 +#define CTA_NAT_SRC 6 +#define CTA_TIMEOUT 7 +#define CTA_MARK 8 +#define CTA_COUNTERS_ORIG 9 +#define CTA_COUNTERS_REPLY 10 +#define CTA_USE 11 +#define CTA_ID 12 +#define CTA_NAT_DST 13 +#define CTA_TUPLE_MASTER 14 +#define CTA_SEQ_ADJ_ORIG 15 +#define CTA_NAT_SEQ_ADJ_ORIG CTA_SEQ_ADJ_ORIG +#define CTA_SEQ_ADJ_REPLY 16 +#define CTA_NAT_SEQ_ADJ_REPLY CTA_SEQ_ADJ_REPLY +#define CTA_ZONE 18 +#define CTA_SECCTX 19 +#define CTA_TIMESTAMP 20 +#define CTA_MARK_MASK 21 +#define CTA_LABELS 22 +#define CTA_LABELS_MASK 23 +#define CTA_SYNPROXY 24 +#define CTA_FILTER 25 +#define CTA_STATUS_MASK 26 +#define CTA_MAX 26 + +/* NETLINK_NETFILTER: Conntrack tuple attributes */ + +#define CTA_TUPLE_UNSPEC 0 +#define CTA_TUPLE_IP 1 +#define CTA_TUPLE_PROTO 2 +#define CTA_TUPLE_ZONE 3 +#define CTA_TUPLE_MAX 3 + +/* NETLINK_NETFILTER: Conntrack IP attributes */ + +#define CTA_IP_UNSPEC 0 +#define CTA_IP_V4_SRC 1 +#define CTA_IP_V4_DST 2 +#define CTA_IP_V6_SRC 3 +#define CTA_IP_V6_DST 4 +#define CTA_IP_MAX 4 + +/* NETLINK_NETFILTER: Conntrack protocol attributes */ + +#define CTA_PROTO_UNSPEC 0 +#define CTA_PROTO_NUM 1 +#define CTA_PROTO_SRC_PORT 2 +#define CTA_PROTO_DST_PORT 3 +#define CTA_PROTO_ICMP_ID 4 +#define CTA_PROTO_ICMP_TYPE 5 +#define CTA_PROTO_ICMP_CODE 6 +#define CTA_PROTO_ICMPV6_ID 7 +#define CTA_PROTO_ICMPV6_TYPE 8 +#define CTA_PROTO_ICMPV6_CODE 9 +#define CTA_PROTO_MAX 9 + +/* NFnetlink multicast groups (userspace) */ + +#define NF_NETLINK_CONNTRACK_NEW 0x00000001 +#define NF_NETLINK_CONNTRACK_UPDATE 0x00000002 +#define NF_NETLINK_CONNTRACK_DESTROY 0x00000004 +#define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 +#define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 +#define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 + +/* NFnetlink multicast groups */ + +#define NFNLGRP_NONE 0 +#define NFNLGRP_CONNTRACK_NEW 1 +#define NFNLGRP_CONNTRACK_UPDATE 2 +#define NFNLGRP_CONNTRACK_DESTROY 3 +#define NFNLGRP_CONNTRACK_EXP_NEW 4 +#define NFNLGRP_CONNTRACK_EXP_UPDATE 5 +#define NFNLGRP_CONNTRACK_EXP_DESTROY 6 +#define NFNLGRP_NFTABLES 7 +#define NFNLGRP_ACCT_QUOTA 8 +#define NFNLGRP_NFTRACE 9 +#define NFNLGRP_MAX 9 + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -584,6 +738,25 @@ struct nla_bitfield32 uint32_t selector; }; +/* NETLINK_NETFILTER Message Structures *************************************/ + +/* These attributes should be manipulated using only the NFA_* */ + +struct nfattr +{ + uint16_t nfa_len; + uint16_t nfa_type; +}; + +/* General form of address family dependent message. */ + +struct nfgenmsg +{ + uint8_t nfgen_family; /* AF_xxx */ + uint8_t version; /* nfnetlink version */ + uint16_t res_id; /* resource id */ +}; + /**************************************************************************** * Neighbor Discovery userland options */ diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c index c961e1de86..6793ecfdcd 100644 --- a/net/nat/ipv4_nat_entry.c +++ b/net/nat/ipv4_nat_entry.c @@ -33,6 +33,7 @@ #include #include "nat/nat.h" +#include "netlink/netlink.h" #ifdef CONFIG_NET_NAT44 @@ -145,6 +146,10 @@ ipv4_nat_entry_create(uint8_t protocol, hashtable_add(g_nat44_outbound, &entry->hash_outbound, ipv4_nat_outbound_key(local_ip, local_port, protocol)); +#ifdef CONFIG_NETLINK_NETFILTER + netlink_conntrack_notify(IPCTNL_MSG_CT_NEW, PF_INET, entry); +#endif + return entry; } @@ -175,6 +180,10 @@ static void ipv4_nat_entry_delete(FAR ipv4_nat_entry_t *entry) entry->local_port, entry->protocol)); +#ifdef CONFIG_NETLINK_NETFILTER + netlink_conntrack_notify(IPCTNL_MSG_CT_DELETE, PF_INET, entry); +#endif + kmm_free(entry); } diff --git a/net/nat/ipv6_nat_entry.c b/net/nat/ipv6_nat_entry.c index e4795380a9..c8f8493faf 100644 --- a/net/nat/ipv6_nat_entry.c +++ b/net/nat/ipv6_nat_entry.c @@ -34,6 +34,7 @@ #include "inet/inet.h" #include "nat/nat.h" +#include "netlink/netlink.h" #ifdef CONFIG_NET_NAT66 @@ -135,6 +136,10 @@ ipv6_nat_entry_create(uint8_t protocol, const net_ipv6addr_t external_ip, hashtable_add(g_nat66_outbound, &entry->hash_outbound, ipv6_nat_hash_key(local_ip, local_port, protocol)); +#ifdef CONFIG_NETLINK_NETFILTER + netlink_conntrack_notify(IPCTNL_MSG_CT_NEW, PF_INET6, entry); +#endif + return entry; } @@ -168,6 +173,10 @@ static void ipv6_nat_entry_delete(FAR ipv6_nat_entry_t *entry) entry->local_port, entry->protocol)); +#ifdef CONFIG_NETLINK_NETFILTER + netlink_conntrack_notify(IPCTNL_MSG_CT_DELETE, PF_INET6, entry); +#endif + kmm_free(entry); } diff --git a/net/netlink/CMakeLists.txt b/net/netlink/CMakeLists.txt index feb14b41af..6f525c6d57 100644 --- a/net/netlink/CMakeLists.txt +++ b/net/netlink/CMakeLists.txt @@ -27,5 +27,9 @@ if(CONFIG_NET_NETLINK) list(APPEND SRCS netlink_route.c netlink_attr.c) endif() + if(CONFIG_NETLINK_NETFILTER) + list(APPEND SRCS netlink_netfilter.c) + endif() + target_sources(net PRIVATE ${SRCS}) endif() diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig index cacf2eaf91..71d60885fd 100644 --- a/net/netlink/Kconfig +++ b/net/netlink/Kconfig @@ -117,6 +117,15 @@ config NETLINK_VALIDATE_POLICY you pass in are valid. endif # NETLINK_ROUTE + +config NETLINK_NETFILTER + bool "Netlink Netfilter protocol" + default n + depends on NET_NAT + ---help--- + Support the NETLINK_NETFILTER protocol option, mainly + for conntrack with NAT. + endmenu # Netlink Protocols endif # NET_NETLINK endmenu # Netlink Socket Support diff --git a/net/netlink/Make.defs b/net/netlink/Make.defs index b18597cca3..363e9f2a93 100644 --- a/net/netlink/Make.defs +++ b/net/netlink/Make.defs @@ -29,6 +29,10 @@ ifeq ($(CONFIG_NETLINK_ROUTE),y) NET_CSRCS += netlink_route.c netlink_attr.c endif +ifeq ($(CONFIG_NETLINK_NETFILTER),y) +NET_CSRCS += netlink_netfilter.c +endif + # Include netlink build support DEPPATH += --dep-path netlink diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h index 320f792438..9e8fc9e584 100644 --- a/net/netlink/netlink.h +++ b/net/netlink/netlink.h @@ -543,7 +543,40 @@ int nla_parse(FAR struct nlattr **tb, int maxtype, FAR const struct nlattr *head, int len, FAR const struct nla_policy *policy, FAR struct netlink_ext_ack *extack); -#endif +#endif /* CONFIG_NETLINK_ROUTE */ + +/**************************************************************************** + * Name: netlink_netfilter_sendto + * + * Description: + * Perform the sendto() operation for the NETLINK_NETFILTER protocol. + * + ****************************************************************************/ + +#ifdef CONFIG_NETLINK_NETFILTER +ssize_t netlink_netfilter_sendto(NETLINK_HANDLE handle, + FAR const struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR const struct sockaddr_nl *to, + socklen_t tolen); + +/**************************************************************************** + * Name: netlink_conntrack_notify + * + * Description: + * Perform the conntrack broadcast for the NETLINK_NETFILTER protocol. + * + * Input Parameters: + * type - The type of the message, IPCTNL_MSG_CT_* + * domain - The domain of the message + * nat_entry - The NAT entry + * + ****************************************************************************/ + +void netlink_conntrack_notify(uint8_t type, uint8_t domain, + FAR const void *nat_entry); + +#endif /* CONFIG_NETLINK_NETFILTER */ #undef EXTERN #ifdef __cplusplus diff --git a/net/netlink/netlink_netfilter.c b/net/netlink/netlink_netfilter.c new file mode 100644 index 0000000000..1fbdc90003 --- /dev/null +++ b/net/netlink/netlink_netfilter.c @@ -0,0 +1,703 @@ +/**************************************************************************** + * net/netlink/netlink_netfilter.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 + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "inet/inet.h" +#include "nat/nat.h" +#include "netlink/netlink.h" +#include "utils/utils.h" + +#ifdef CONFIG_NETLINK_NETFILTER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nfnl_sendto_request_s +{ + struct nlmsghdr hdr; + struct nfgenmsg msg; +}; + +struct nfnl_info_s +{ + NETLINK_HANDLE handle; + FAR const struct nfnl_sendto_request_s *req; +}; + +struct nfnl_ipv4addr_s +{ + struct nfattr attr; + in_addr_t addr; +}; + +struct nfnl_ipv6addr_s +{ + struct nfattr attr; + net_ipv6addr_t addr; +}; + +struct nfnl_attr_u8_s +{ + struct nfattr attr; + uint8_t value; + uint8_t pad[3]; +}; + +struct nfnl_attr_u16_s +{ + struct nfattr attr; + uint16_t value; + uint16_t pad[1]; +}; + +/* Struct of a conntrack tuple + * +------+--------------+-----------------+ + * | attr | CTA_TUPLE_IP | CTA_TUPLE_PROTO | + * +------+--------------+-----------------+ + */ + +/* CTA_TUPLE_IP definitions */ + +struct conntrack_tuple_ipv4_s +{ + struct nfattr attr; + struct nfnl_ipv4addr_s src; + struct nfnl_ipv4addr_s dst; +}; + +struct conntrack_tuple_ipv6_s +{ + struct nfattr attr; + struct nfnl_ipv6addr_s src; + struct nfnl_ipv6addr_s dst; +}; + +/* CTA_TUPLE_PROTO definitions */ + +struct conntrack_tuple_tcpudp_s +{ + struct nfattr attr; + struct nfnl_attr_u8_s proto; + struct nfnl_attr_u16_s sport; + struct nfnl_attr_u16_s dport; +}; + +struct conntrack_tuple_icmp_s +{ + struct nfattr attr; + struct nfnl_attr_u8_s proto; + struct nfnl_attr_u16_s id; + struct nfnl_attr_u8_s type; + struct nfnl_attr_u8_s code; +}; + +/* Struct of a conntrack response + * +-----+-----+-----------------+----------------+ + * | hdr | msg | tuple of origin | tuple of reply | + * +-----+-----+-----------------+----------------+ + */ + +struct conntrack_recvfrom_response_s +{ + struct nlmsghdr hdr; + struct nfgenmsg msg; + uint8_t data[1]; +}; + +#define SIZEOF_CTNL_RECVFROM_RESPONSE_S(n) \ + (sizeof(struct conntrack_recvfrom_response_s) + (n) - 1) + +struct conntrack_recvfrom_rsplist_s +{ + sq_entry_t flink; + struct conntrack_recvfrom_response_s payload; +}; + +#define SIZEOF_CTNL_RECVFROM_RSPLIST_S(n) \ + (sizeof(struct conntrack_recvfrom_rsplist_s) + (n) - 1) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlink_conntrack_tuple_size + * + * Description: + * Get the size of a CTA_TUPLE. Struct of a conntrack tuple: + * +------+--------------+-----------------+ + * | attr | CTA_TUPLE_IP | CTA_TUPLE_PROTO | + * +------+--------------+-----------------+ + * + * Input Parameters: + * domain - The domain of the tuple + * proto - The protocol of the tuple + * + * Returned Value: + * The size of the tuple. + * + ****************************************************************************/ + +static ssize_t netlink_conntrack_tuple_size(uint8_t domain, uint8_t proto) +{ + size_t size = sizeof(struct nfattr); + + switch (domain) + { + case PF_INET: + size += sizeof(struct conntrack_tuple_ipv4_s); + break; + + case PF_INET6: + size += sizeof(struct conntrack_tuple_ipv6_s); + break; + + default: + return -EINVAL; + } + + switch (proto) + { + case IPPROTO_TCP: + case IPPROTO_UDP: + size += sizeof(struct conntrack_tuple_tcpudp_s); + break; + + case IPPROTO_ICMP: + case IPPROTO_ICMP6: + size += sizeof(struct conntrack_tuple_icmp_s); + break; + + default: + return -EINVAL; + } + + return size; +} + +/**************************************************************************** + * Name: netlink_conntrack_fill_ip + * + * Description: + * Fill the data of a CTA_TUPLE_IP. + * + * Input Parameters: + * buf - The buffer to fill + * domain - The domain of the addresses + * src - The source address + * dst - The destination address + * + * Returned Value: + * The size of the filled data. + * + ****************************************************************************/ + +static size_t netlink_conntrack_fill_ip(FAR void *buf, uint8_t domain, + FAR const void *src, + FAR const void *dst) +{ +#ifdef CONFIG_NET_NAT44 + if (domain == PF_INET) + { + FAR struct conntrack_tuple_ipv4_s *tuple_ipv4 = buf; + + tuple_ipv4->attr.nfa_len = sizeof(struct conntrack_tuple_ipv4_s); + tuple_ipv4->attr.nfa_type = CTA_TUPLE_IP | NFNL_NFA_NEST; + + tuple_ipv4->src.attr.nfa_len = NFA_LENGTH(sizeof(in_addr_t)); + tuple_ipv4->src.attr.nfa_type = CTA_IP_V4_SRC; + net_ipv4addr_hdrcopy(&tuple_ipv4->src.addr, src); + + tuple_ipv4->dst.attr.nfa_len = NFA_LENGTH(sizeof(in_addr_t)); + tuple_ipv4->dst.attr.nfa_type = CTA_IP_V4_DST; + net_ipv4addr_hdrcopy(&tuple_ipv4->dst.addr, dst); + + return tuple_ipv4->attr.nfa_len; + } +#endif + +#ifdef CONFIG_NET_NAT66 + if (domain == PF_INET6) + { + FAR struct conntrack_tuple_ipv6_s *tuple_ipv6 = buf; + + tuple_ipv6->attr.nfa_len = sizeof(struct conntrack_tuple_ipv6_s); + tuple_ipv6->attr.nfa_type = CTA_TUPLE_IP | NFNL_NFA_NEST; + + tuple_ipv6->src.attr.nfa_len = NFA_LENGTH(sizeof(net_ipv6addr_t)); + tuple_ipv6->src.attr.nfa_type = CTA_IP_V6_SRC; + net_ipv6addr_hdrcopy(tuple_ipv6->src.addr, src); + + tuple_ipv6->dst.attr.nfa_len = NFA_LENGTH(sizeof(net_ipv6addr_t)); + tuple_ipv6->dst.attr.nfa_type = CTA_IP_V6_DST; + net_ipv6addr_hdrcopy(tuple_ipv6->dst.addr, dst); + + return tuple_ipv6->attr.nfa_len; + } +#endif + + return 0; +} + +/**************************************************************************** + * Name: netlink_conntrack_fill_proto + * + * Description: + * Fill the data of a CTA_TUPLE_PROTO. + * + * Input Parameters: + * buf - The buffer to fill + * proto - The protocol of the tuple + * sport - The source port + * dport - The destination port + * reply - True if the tuple is a reply + * + * Returned Value: + * The size of the filled data. + * + ****************************************************************************/ + +static size_t netlink_conntrack_fill_proto(FAR void *buf, uint8_t proto, + uint16_t sport, uint16_t dport, + bool reply) +{ + switch (proto) + { +#ifdef CONFIG_NET_TCP + case IPPROTO_TCP: +#endif +#ifdef CONFIG_NET_UDP + case IPPROTO_UDP: +#endif +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) + { + FAR struct conntrack_tuple_tcpudp_s *tuple_tcpudp = buf; + + tuple_tcpudp->attr.nfa_len = + sizeof(struct conntrack_tuple_tcpudp_s); + tuple_tcpudp->attr.nfa_type = CTA_TUPLE_PROTO | NFNL_NFA_NEST; + + tuple_tcpudp->proto.attr.nfa_len = NFA_LENGTH(sizeof(uint8_t)); + tuple_tcpudp->proto.attr.nfa_type = CTA_PROTO_NUM; + tuple_tcpudp->proto.value = proto; + + tuple_tcpudp->sport.attr.nfa_len = NFA_LENGTH(sizeof(uint16_t)); + tuple_tcpudp->sport.attr.nfa_type = CTA_PROTO_SRC_PORT; + tuple_tcpudp->sport.value = sport; + + tuple_tcpudp->dport.attr.nfa_len = NFA_LENGTH(sizeof(uint16_t)); + tuple_tcpudp->dport.attr.nfa_type = CTA_PROTO_DST_PORT; + tuple_tcpudp->dport.value = dport; + + return tuple_tcpudp->attr.nfa_len; + } +#endif + +#ifdef CONFIG_NET_ICMP + case IPPROTO_ICMP: +#endif +#ifdef CONFIG_NET_ICMPv6 + case IPPROTO_ICMP6: +#endif +#if defined(CONFIG_NET_ICMP) || defined(CONFIG_NET_ICMPv6) + { + FAR struct conntrack_tuple_icmp_s *tuple_icmp = buf; + + tuple_icmp->attr.nfa_len = sizeof(struct conntrack_tuple_icmp_s); + tuple_icmp->attr.nfa_type = CTA_TUPLE_PROTO | NFNL_NFA_NEST; + + tuple_icmp->proto.attr.nfa_len = NFA_LENGTH(sizeof(uint8_t)); + tuple_icmp->proto.attr.nfa_type = CTA_PROTO_NUM; + tuple_icmp->proto.value = proto; + + tuple_icmp->id.attr.nfa_len = NFA_LENGTH(sizeof(uint16_t)); + tuple_icmp->id.value = reply ? dport : sport; + + tuple_icmp->type.attr.nfa_len = NFA_LENGTH(sizeof(uint8_t)); + + tuple_icmp->code.attr.nfa_len = NFA_LENGTH(sizeof(uint8_t)); + tuple_icmp->code.value = 0; + +#ifdef CONFIG_NET_ICMP + if (proto == IPPROTO_ICMP) + { + tuple_icmp->id.attr.nfa_type = CTA_PROTO_ICMP_ID; + tuple_icmp->type.attr.nfa_type = CTA_PROTO_ICMP_TYPE; + tuple_icmp->type.value = reply ? ICMP_ECHO_REPLY : + ICMP_ECHO_REQUEST; + tuple_icmp->code.attr.nfa_type = CTA_PROTO_ICMP_CODE; + } +#endif + +#ifdef CONFIG_NET_ICMPv6 + if (proto == IPPROTO_ICMP6) + { + tuple_icmp->id.attr.nfa_type = CTA_PROTO_ICMPV6_ID; + tuple_icmp->type.attr.nfa_type = CTA_PROTO_ICMPV6_TYPE; + tuple_icmp->type.value = reply ? ICMPv6_ECHO_REPLY : + ICMPv6_ECHO_REQUEST; + tuple_icmp->code.attr.nfa_type = CTA_PROTO_ICMPV6_CODE; + } +#endif + + return tuple_icmp->attr.nfa_len; + } +#endif + } + + return 0; +} + +/**************************************************************************** + * Name: netlink_get_ipv4/ipv6_conntrack + * + * Description: + * Get the conntrack response corresponding to an NAT entry. + * + ****************************************************************************/ + +static FAR struct netlink_response_s * +netlink_get_conntrack(FAR const struct nlmsghdr *req, uint16_t flags, + uint8_t type, uint8_t domain, uint8_t proto, + FAR const void *lipaddr, uint16_t lport, + FAR const void *eipaddr, uint16_t eport, + FAR const void *ripaddr, uint16_t rport) +{ + FAR struct conntrack_recvfrom_rsplist_s *entry; + FAR struct nfattr *tuple; + ssize_t tuple_size = netlink_conntrack_tuple_size(domain, proto); + size_t offset = 0; + size_t allocsize; + size_t rspsize; + + if (tuple_size < 0) + { + nerr("ERROR: Failed to get tuple size in response.\n"); + return NULL; + } + + rspsize = SIZEOF_CTNL_RECVFROM_RESPONSE_S(tuple_size * 2); + allocsize = SIZEOF_CTNL_RECVFROM_RSPLIST_S(tuple_size * 2); + + entry = kmm_malloc(allocsize); + if (entry == NULL) + { + nerr("ERROR: Failed to allocate response buffer.\n"); + return NULL; + } + + entry->payload.hdr.nlmsg_len = rspsize; + entry->payload.hdr.nlmsg_type = type | (NFNL_SUBSYS_CTNETLINK << 8); + entry->payload.hdr.nlmsg_flags = flags; + entry->payload.hdr.nlmsg_seq = req ? req->nlmsg_seq : 0; + entry->payload.hdr.nlmsg_pid = req ? req->nlmsg_pid : 0; + + entry->payload.msg.nfgen_family = domain; + entry->payload.msg.version = NFNETLINK_V0; + entry->payload.msg.res_id = 0; + + /* CTA_TUPLE_ORIG */ + + tuple = (FAR struct nfattr *)&entry->payload.data[offset]; + tuple->nfa_len = tuple_size; + tuple->nfa_type = CTA_TUPLE_ORIG | NFNL_NFA_NEST; + offset += sizeof(struct nfattr); + + offset += netlink_conntrack_fill_ip(&entry->payload.data[offset], domain, + lipaddr, ripaddr); + offset += netlink_conntrack_fill_proto(&entry->payload.data[offset], proto, + lport, rport, false); + + DEBUGASSERT(offset == tuple_size); + + /* CTA_TUPLE_REPLY */ + + tuple = (FAR struct nfattr *)&entry->payload.data[offset]; + tuple->nfa_len = tuple_size; + tuple->nfa_type = CTA_TUPLE_REPLY | NFNL_NFA_NEST; + offset += sizeof(struct nfattr); + + offset += netlink_conntrack_fill_ip(&entry->payload.data[offset], domain, + ripaddr, eipaddr); + offset += netlink_conntrack_fill_proto(&entry->payload.data[offset], proto, + rport, eport, true); + + DEBUGASSERT(offset == tuple_size * 2); + + return (FAR struct netlink_response_s *)entry; +} + +#ifdef CONFIG_NET_NAT44 +static FAR struct netlink_response_s * +netlink_get_ipv4_conntrack(FAR const struct nlmsghdr *req, + FAR const ipv4_nat_entry_t *entry, + uint16_t flags, uint8_t type) +{ +#ifndef CONFIG_NET_NAT44_SYMMETRIC + const in_addr_t any = INADDR_ANY; +#endif + return netlink_get_conntrack(req, flags, type, PF_INET, entry->protocol, + &entry->local_ip, entry->local_port, + &entry->external_ip, entry->external_port, +#ifdef CONFIG_NET_NAT44_SYMMETRIC + &entry->peer_ip, entry->peer_port +#else + &any, 0 /* Zero-address */ +#endif + ); +} +#endif + +#ifdef CONFIG_NET_NAT66 +static FAR struct netlink_response_s * +netlink_get_ipv6_conntrack(FAR const struct nlmsghdr *req, + FAR const ipv6_nat_entry_t *entry, + uint16_t flags, uint8_t type) +{ + return netlink_get_conntrack(req, flags, type, PF_INET6, entry->protocol, + entry->local_ip, entry->local_port, + entry->external_ip, entry->external_port, +#ifdef CONFIG_NET_NAT66_SYMMETRIC + entry->peer_ip, entry->peer_port +#else + g_ipv6_unspecaddr, 0 /* Zero-address */ +#endif + ); +} +#endif + +/**************************************************************************** + * Name: netlink_add_ipv4/ipv6_conntrack + * + * Description: + * Add the conntrack response of an IPv4/IPv6 NAT entry. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_NAT44 +static void netlink_add_ipv4_conntrack(FAR ipv4_nat_entry_t *entry, + FAR void *arg) +{ + FAR struct nfnl_info_s *info = arg; + FAR struct netlink_response_s *resp; + uint16_t flags = NLM_F_MULTI | NLM_F_DUMP_FILTERED; + + resp = netlink_get_ipv4_conntrack(&info->req->hdr, entry, flags, + IPCTNL_MSG_CT_NEW); + if (resp != NULL) + { + netlink_add_response(info->handle, resp); + } +} +#endif + +#ifdef CONFIG_NET_NAT66 +static void netlink_add_ipv6_conntrack(FAR ipv6_nat_entry_t *entry, + FAR void *arg) +{ + FAR struct nfnl_info_s *info = arg; + FAR struct netlink_response_s *resp; + uint16_t flags = NLM_F_MULTI | NLM_F_DUMP_FILTERED; + + resp = netlink_get_ipv6_conntrack(&info->req->hdr, entry, flags, + IPCTNL_MSG_CT_NEW); + + if (resp != NULL) + { + netlink_add_response(info->handle, resp); + } +} +#endif + +/**************************************************************************** + * Name: netlink_list_conntrack + * + * Description: + * Return the entire NAT table. + * + ****************************************************************************/ + +static int netlink_list_conntrack(NETLINK_HANDLE handle, + FAR const struct nfnl_sendto_request_s *req) +{ + struct nfnl_info_s info; + uint8_t type = NFNL_MSG_TYPE(req->hdr.nlmsg_type); + if (type != IPCTNL_MSG_CT_GET) + { + return -ENOSYS; + } + + info.handle = handle; + info.req = req; + + switch (req->msg.nfgen_family) + { +#ifdef CONFIG_NET_NAT44 + case AF_INET: + ipv4_nat_entry_foreach(netlink_add_ipv4_conntrack, &info); + break; +#endif + +#ifdef CONFIG_NET_NAT66 + case AF_INET6: + ipv6_nat_entry_foreach(netlink_add_ipv6_conntrack, &info); + break; +#endif + + default: + return -ENOSYS; + } + + return netlink_add_terminator(handle, &req->hdr, 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlink_netfilter_sendto + * + * Description: + * Perform the sendto() operation for the NETLINK_NETFILTER protocol. + * + ****************************************************************************/ + +ssize_t netlink_netfilter_sendto(NETLINK_HANDLE handle, + FAR const struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR const struct sockaddr_nl *to, + socklen_t tolen) +{ + FAR const struct nfnl_sendto_request_s *req = + (FAR const struct nfnl_sendto_request_s *)nlmsg; + ssize_t ret = -ENOSYS; + uint8_t subsys; + + DEBUGASSERT(handle != NULL && nlmsg != NULL && + nlmsg->nlmsg_len >= sizeof(struct nlmsghdr) && + len >= sizeof(struct nlmsghdr) && + len >= nlmsg->nlmsg_len && to != NULL && + tolen >= sizeof(struct sockaddr_nl)); + + /* Split subsys and type from nlmsg->nlmsg_type */ + + subsys = NFNL_SUBSYS_ID(nlmsg->nlmsg_type); + + /* Handle according to the subsystem */ + + switch (subsys) + { + case NFNL_SUBSYS_CTNETLINK: + ret = netlink_list_conntrack(handle, req); + break; + } + + /* On success, return the size of the request that was processed */ + + if (ret >= 0) + { + ret = len; + } + + return ret; +} + +/**************************************************************************** + * Name: netlink_conntrack_notify + * + * Description: + * Perform the conntrack broadcast for the NETLINK_NETFILTER protocol. + * + * Input Parameters: + * type - The type of the message, IPCTNL_MSG_CT_* + * domain - The domain of the message + * nat_entry - The NAT entry + * + ****************************************************************************/ + +void netlink_conntrack_notify(uint8_t type, uint8_t domain, + FAR const void *nat_entry) +{ + FAR struct netlink_response_s *resp; + uint16_t flags; + int group; + + switch (type) + { + case IPCTNL_MSG_CT_NEW: + group = NFNLGRP_CONNTRACK_NEW; + flags = NLM_F_EXCL | NLM_F_CREATE; + break; + + case IPCTNL_MSG_CT_DELETE: + group = NFNLGRP_CONNTRACK_DESTROY; + flags = 0; + break; + + default: + return; + } + + switch (domain) + { +#ifdef CONFIG_NET_NAT44 + case PF_INET: + resp = netlink_get_ipv4_conntrack(NULL, nat_entry, flags, type); + break; +#endif + +#ifdef CONFIG_NET_NAT66 + case PF_INET6: + resp = netlink_get_ipv6_conntrack(NULL, nat_entry, flags, type); + break; +#endif + + default: + return; + } + + if (resp != NULL) + { + netlink_add_broadcast(group, resp); + } +} + +#endif /* CONFIG_NETLINK_NETFILTER */ diff --git a/net/netlink/netlink_sockif.c b/net/netlink/netlink_sockif.c index abfa27d9fc..72de037697 100644 --- a/net/netlink/netlink_sockif.c +++ b/net/netlink/netlink_sockif.c @@ -129,6 +129,11 @@ static int netlink_setup(FAR struct socket *psock) break; #endif +#ifdef CONFIG_NETLINK_NETFILTER + case NETLINK_NETFILTER: + break; +#endif + default: return -EPROTONOSUPPORT; } @@ -621,6 +626,15 @@ static ssize_t netlink_sendmsg(FAR struct socket *psock, break; #endif +#ifdef CONFIG_NETLINK_NETFILTER + case NETLINK_NETFILTER: + ret = netlink_netfilter_sendto(conn, nlmsg, + msg->msg_iov->iov_len, flags, + (FAR const struct sockaddr_nl *)to, + tolen); + break; +#endif + default: ret = -EOPNOTSUPP; break;