diff --git a/net/ipforward/ipv4_forward.c b/net/ipforward/ipv4_forward.c index 8da46a528cb..3ad51144596 100644 --- a/net/ipforward/ipv4_forward.c +++ b/net/ipforward/ipv4_forward.c @@ -37,6 +37,7 @@ #include "netdev/netdev.h" #include "utils/utils.h" #include "sixlowpan/sixlowpan.h" +#include "icmp/icmp.h" #include "ipforward/ipforward.h" #include "nat/nat.h" #include "devif/devif.h" @@ -148,12 +149,6 @@ static int ipv4_decr_ttl(FAR struct ipv4_hdr_s *ipv4) ttl = (int)ipv4->ttl - 1; if (ttl <= 0) { -#ifdef CONFIG_NET_ICMP - /* Return an ICMP error packet back to the sender. */ - -# warning Missing logic -#endif - /* Return zero which must cause the packet to be dropped */ return 0; @@ -317,7 +312,8 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev, /* Try NAT outbound, rule matching will be performed in NAT module. */ ret = ipv4_nat_outbound(fwd->f_dev, - (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data); + (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data, + NAT_MANIP_SRC); if (ret < 0) { nwarn("WARNING: Performing NAT outbound failed, dropping!\n"); @@ -444,6 +440,10 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4) in_addr_t srcipaddr; FAR struct net_driver_s *fwddev; int ret; +#ifdef CONFIG_NET_ICMP + int icmp_reply_type; + int icmp_reply_code; +#endif /* CONFIG_NET_ICMP */ /* Search for a device that can forward this packet. */ @@ -454,7 +454,8 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4) if (fwddev == NULL) { nwarn("WARNING: Not routable\n"); - return (ssize_t)-ENETUNREACH; + ret = -ENETUNREACH; + goto drop; } /* Check if we are forwarding on the same device that we received the @@ -505,8 +506,48 @@ int ipv4_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4) drop: ipv4_dropstats(ipv4); + +#ifdef CONFIG_NET_ICMP + /* Reply ICMP to the sender for particular errors. */ + + switch (ret) + { + case -ENETUNREACH: + icmp_reply_type = ICMP_DEST_UNREACHABLE; + icmp_reply_code = ICMP_NET_UNREACH; + goto reply; + + case -EFBIG: + icmp_reply_type = ICMP_DEST_UNREACHABLE; + icmp_reply_code = ICMP_FRAG_NEEDED; + goto reply; + + case -EMULTIHOP: + icmp_reply_type = ICMP_TIME_EXCEEDED; + icmp_reply_code = 0; + goto reply; + + default: + break; /* We don't know how to reply, just go on (to drop). */ + } +#endif /* CONFIG_NET_ICMP */ + dev->d_len = 0; return ret; + +#ifdef CONFIG_NET_ICMP +reply: +# ifdef CONFIG_NET_NAT + /* Before we reply ICMP, call NAT outbound to try to translate destination + * address & port back to original status. + */ + + ipv4_nat_outbound(dev, ipv4, NAT_MANIP_DST); +# endif /* CONFIG_NET_NAT */ + + icmp_reply(dev, icmp_reply_type, icmp_reply_code); + return OK; +#endif /* CONFIG_NET_ICMP */ } /**************************************************************************** diff --git a/net/nat/ipv4_nat.c b/net/nat/ipv4_nat.c index 0574fd7bd8b..f2f00d35e6e 100644 --- a/net/nat/ipv4_nat.c +++ b/net/nat/ipv4_nat.c @@ -76,20 +76,6 @@ # define L4_MAXHDRLEN ICMP_HDRLEN #endif -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* NAT IP/Port manipulate type, to indicate whether to manipulate source or - * destination IP/Port in a packet. - */ - -enum nat_manip_type_e -{ - NAT_MANIP_SRC, - NAT_MANIP_DST -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -790,6 +776,7 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev, * Input Parameters: * dev - The device on which the packet will be sent. * ipv4 - Points to the IPv4 header to be filled into dev->d_buf later. + * manip_type - Whether local IP/Port is in source or destination. * * Returned Value: * Zero is returned if NAT is successfully applied, or is not enabled for @@ -799,20 +786,22 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev, ****************************************************************************/ int ipv4_nat_outbound(FAR struct net_driver_s *dev, - FAR struct ipv4_hdr_s *ipv4) + FAR struct ipv4_hdr_s *ipv4, + enum nat_manip_type_e manip_type) { /* We only process packets targeting at NAT device but not targeting at the * address assigned to the device. */ if (IFF_IS_NAT(dev->d_flags) && + !net_ipv4addr_hdrcmp(ipv4->srcipaddr, &dev->d_ipaddr) && !net_ipv4addr_hdrcmp(ipv4->destipaddr, &dev->d_ipaddr)) { /* TODO: Skip broadcast? */ FAR struct ipv4_nat_entry *entry = - ipv4_nat_outbound_internal(dev, ipv4, NAT_MANIP_SRC); - if (!entry) + ipv4_nat_outbound_internal(dev, ipv4, manip_type); + if (manip_type == NAT_MANIP_SRC && !entry) { /* Outbound entry creation failed, should have entry. */ diff --git a/net/nat/nat.h b/net/nat/nat.h index e4e440148ed..d65a7c85964 100644 --- a/net/nat/nat.h +++ b/net/nat/nat.h @@ -71,6 +71,16 @@ struct ipv4_nat_entry uint32_t expire_time; /* The expiration time of this entry. */ }; +/* NAT IP/Port manipulate type, to indicate whether to manipulate source or + * destination IP/Port in a packet. + */ + +enum nat_manip_type_e +{ + NAT_MANIP_SRC, + NAT_MANIP_DST +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -147,6 +157,7 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev, * Input Parameters: * dev - The device on which the packet will be sent. * ipv4 - Points to the IPv4 header to be filled into dev->d_buf later. + * manip_type - Whether local IP/Port is in source or destination. * * Returned Value: * Zero is returned if NAT is successfully applied, or is not enabled for @@ -156,7 +167,8 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev, ****************************************************************************/ int ipv4_nat_outbound(FAR struct net_driver_s *dev, - FAR struct ipv4_hdr_s *ipv4); + FAR struct ipv4_hdr_s *ipv4, + enum nat_manip_type_e manip_type); /**************************************************************************** * Name: ipv4_nat_port_inuse