Home | History | Annotate | Line # | Download | only in npf
npf_alg_icmp.c revision 1.8.4.3.2.1
      1  1.8.4.3.2.1    matt /*	$NetBSD: npf_alg_icmp.c,v 1.8.4.3.2.1 2012/11/01 16:45:03 matt Exp $	*/
      2          1.1   rmind 
      3          1.1   rmind /*-
      4          1.1   rmind  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5          1.1   rmind  * All rights reserved.
      6          1.1   rmind  *
      7          1.1   rmind  * This material is based upon work partially supported by The
      8          1.1   rmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
      9          1.1   rmind  *
     10          1.1   rmind  * Redistribution and use in source and binary forms, with or without
     11          1.1   rmind  * modification, are permitted provided that the following conditions
     12          1.1   rmind  * are met:
     13          1.1   rmind  * 1. Redistributions of source code must retain the above copyright
     14          1.1   rmind  *    notice, this list of conditions and the following disclaimer.
     15          1.1   rmind  * 2. Redistributions in binary form must reproduce the above copyright
     16          1.1   rmind  *    notice, this list of conditions and the following disclaimer in the
     17          1.1   rmind  *    documentation and/or other materials provided with the distribution.
     18          1.1   rmind  *
     19          1.1   rmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20          1.1   rmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21          1.1   rmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22          1.1   rmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23          1.1   rmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24          1.1   rmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25          1.1   rmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26          1.1   rmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27          1.1   rmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28          1.1   rmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29          1.1   rmind  * POSSIBILITY OF SUCH DAMAGE.
     30          1.1   rmind  */
     31          1.1   rmind 
     32          1.1   rmind /*
     33          1.1   rmind  * NPF ALG for ICMP and traceroute translations.
     34          1.1   rmind  */
     35          1.1   rmind 
     36          1.1   rmind #include <sys/cdefs.h>
     37  1.8.4.3.2.1    matt __KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.8.4.3.2.1 2012/11/01 16:45:03 matt Exp $");
     38          1.1   rmind 
     39          1.1   rmind #include <sys/param.h>
     40          1.1   rmind #include <sys/module.h>
     41          1.1   rmind #include <sys/pool.h>
     42          1.1   rmind 
     43          1.1   rmind #include <netinet/in_systm.h>
     44          1.1   rmind #include <netinet/in.h>
     45          1.1   rmind #include <netinet/ip.h>
     46          1.1   rmind #include <netinet/tcp.h>
     47          1.1   rmind #include <netinet/udp.h>
     48          1.1   rmind #include <netinet/ip_icmp.h>
     49      1.8.4.3     jdc #include <netinet/icmp6.h>
     50          1.1   rmind #include <net/pfil.h>
     51          1.1   rmind 
     52          1.1   rmind #include "npf_impl.h"
     53          1.1   rmind 
     54          1.1   rmind MODULE(MODULE_CLASS_MISC, npf_alg_icmp, "npf");
     55          1.1   rmind 
     56          1.1   rmind /*
     57          1.1   rmind  * Traceroute criteria.
     58          1.1   rmind  *
     59          1.1   rmind  * IANA assigned base port: 33434.  However, common practice is to increase
     60          1.1   rmind  * the port, thus monitor [33434-33484] range.  Additional filter is TTL < 50.
     61          1.1   rmind  */
     62          1.1   rmind 
     63          1.1   rmind #define	TR_BASE_PORT	33434
     64          1.1   rmind #define	TR_PORT_RANGE	33484
     65          1.1   rmind #define	TR_MAX_TTL	50
     66          1.1   rmind 
     67          1.6   rmind static npf_alg_t *	alg_icmp	__read_mostly;
     68          1.1   rmind 
     69          1.1   rmind static bool		npfa_icmp_match(npf_cache_t *, nbuf_t *, void *);
     70          1.1   rmind static bool		npfa_icmp_natin(npf_cache_t *, nbuf_t *, void *);
     71          1.1   rmind static bool		npfa_icmp_session(npf_cache_t *, nbuf_t *, void *);
     72          1.1   rmind 
     73          1.1   rmind /*
     74          1.1   rmind  * npf_alg_icmp_{init,fini,modcmd}: ICMP ALG initialization, destruction
     75          1.1   rmind  * and module interface.
     76          1.1   rmind  */
     77          1.1   rmind 
     78          1.1   rmind static int
     79          1.1   rmind npf_alg_icmp_init(void)
     80          1.1   rmind {
     81          1.1   rmind 
     82          1.1   rmind 	alg_icmp = npf_alg_register(npfa_icmp_match, NULL,
     83          1.1   rmind 	    npfa_icmp_natin, npfa_icmp_session);
     84          1.1   rmind 	KASSERT(alg_icmp != NULL);
     85          1.1   rmind 	return 0;
     86          1.1   rmind }
     87          1.1   rmind 
     88          1.1   rmind static int
     89          1.1   rmind npf_alg_icmp_fini(void)
     90          1.1   rmind {
     91          1.1   rmind 
     92          1.1   rmind 	KASSERT(alg_icmp != NULL);
     93          1.1   rmind 	return npf_alg_unregister(alg_icmp);
     94          1.1   rmind }
     95          1.1   rmind 
     96          1.1   rmind static int
     97          1.1   rmind npf_alg_icmp_modcmd(modcmd_t cmd, void *arg)
     98          1.1   rmind {
     99          1.1   rmind 
    100          1.1   rmind 	switch (cmd) {
    101          1.1   rmind 	case MODULE_CMD_INIT:
    102          1.1   rmind 		return npf_alg_icmp_init();
    103          1.1   rmind 	case MODULE_CMD_FINI:
    104          1.1   rmind 		return npf_alg_icmp_fini();
    105      1.8.4.2     riz 	case MODULE_CMD_AUTOUNLOAD:
    106      1.8.4.2     riz 		return EBUSY;
    107          1.1   rmind 	default:
    108          1.1   rmind 		return ENOTTY;
    109          1.1   rmind 	}
    110          1.1   rmind 	return 0;
    111          1.1   rmind }
    112          1.1   rmind 
    113          1.1   rmind /*
    114          1.4   rmind  * npfa_icmp_match: ALG matching inspector - determines ALG case and
    115          1.4   rmind  * associates ALG with NAT entry.
    116          1.1   rmind  */
    117          1.1   rmind static bool
    118          1.1   rmind npfa_icmp_match(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
    119          1.1   rmind {
    120          1.4   rmind 	const int proto = npf_cache_ipproto(npc);
    121          1.4   rmind 	struct ip *ip = &npc->npc_ip.v4;
    122          1.4   rmind 	in_port_t dport;
    123          1.4   rmind 
    124          1.7  zoltan 	KASSERT(npf_iscached(npc, NPC_IP46));
    125          1.7  zoltan 	KASSERT(npf_iscached(npc, NPC_LAYER4));
    126          1.4   rmind 
    127          1.6   rmind 	/* Check for low TTL. */
    128          1.6   rmind 	if (ip->ip_ttl > TR_MAX_TTL) {
    129          1.6   rmind 		return false;
    130          1.6   rmind 	}
    131          1.6   rmind 
    132          1.4   rmind 	if (proto == IPPROTO_TCP) {
    133          1.4   rmind 		struct tcphdr *th = &npc->npc_l4.tcp;
    134          1.4   rmind 		dport = ntohs(th->th_dport);
    135          1.4   rmind 	} else if (proto == IPPROTO_UDP) {
    136          1.4   rmind 		struct udphdr *uh = &npc->npc_l4.udp;
    137          1.4   rmind 		dport = ntohs(uh->uh_dport);
    138          1.4   rmind 	} else {
    139          1.4   rmind 		return false;
    140          1.4   rmind 	}
    141          1.1   rmind 
    142          1.1   rmind 	/* Handle TCP/UDP traceroute - check for port range. */
    143          1.1   rmind 	if (dport < TR_BASE_PORT || dport > TR_PORT_RANGE) {
    144          1.1   rmind 		return false;
    145          1.1   rmind 	}
    146          1.1   rmind 
    147          1.1   rmind 	/* Associate ALG with translation entry. */
    148          1.1   rmind 	npf_nat_t *nt = ntptr;
    149          1.1   rmind 	npf_nat_setalg(nt, alg_icmp, 0);
    150          1.1   rmind 	return true;
    151          1.1   rmind }
    152          1.1   rmind 
    153          1.1   rmind /*
    154          1.1   rmind  * npf_icmp_uniqid: retrieve unique identifiers - either ICMP query ID
    155          1.1   rmind  * or TCP/UDP ports of the original packet, which is embedded.
    156          1.1   rmind  */
    157          1.5   rmind static bool
    158  1.8.4.3.2.1    matt npf_icmp_uniqid(const int npcinf, const int type,
    159  1.8.4.3.2.1    matt     npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
    160          1.1   rmind {
    161      1.8.4.3     jdc 	struct icmp      *ic;
    162      1.8.4.3     jdc 	struct icmp6_hdr *ic6;
    163      1.8.4.3     jdc 	u_int            offby;
    164      1.8.4.3     jdc 
    165  1.8.4.3.2.1    matt 	if (npcinf & NPC_IP4) {
    166      1.8.4.3     jdc 		/* Per RFC 792. */
    167      1.8.4.3     jdc 		switch (type) {
    168      1.8.4.3     jdc 		case ICMP_UNREACH:
    169      1.8.4.3     jdc 		case ICMP_SOURCEQUENCH:
    170      1.8.4.3     jdc 		case ICMP_REDIRECT:
    171      1.8.4.3     jdc 		case ICMP_TIMXCEED:
    172      1.8.4.3     jdc 		case ICMP_PARAMPROB:
    173      1.8.4.3     jdc 			/* Should contain original IP header. */
    174      1.8.4.3     jdc 			offby = offsetof(struct icmp, icmp_ip);
    175      1.8.4.3     jdc 			if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
    176      1.8.4.3     jdc 				return false;
    177      1.8.4.3     jdc 			}
    178      1.8.4.3     jdc 			/* Fetch into the cache. */
    179      1.8.4.3     jdc 			if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
    180      1.8.4.3     jdc 				return false;
    181      1.8.4.3     jdc 			}
    182      1.8.4.3     jdc 			switch (npf_cache_ipproto(npc)) {
    183      1.8.4.3     jdc 			case IPPROTO_TCP:
    184      1.8.4.3     jdc 				return npf_fetch_tcp(npc, nbuf, n_ptr);
    185      1.8.4.3     jdc 			case IPPROTO_UDP:
    186      1.8.4.3     jdc 				return npf_fetch_udp(npc, nbuf, n_ptr);
    187      1.8.4.3     jdc 			default:
    188      1.8.4.3     jdc 				return false;
    189      1.8.4.3     jdc 			}
    190      1.8.4.3     jdc 			return true;
    191      1.8.4.3     jdc 
    192      1.8.4.3     jdc 		case ICMP_ECHOREPLY:
    193      1.8.4.3     jdc 		case ICMP_ECHO:
    194      1.8.4.3     jdc 		case ICMP_TSTAMP:
    195      1.8.4.3     jdc 		case ICMP_TSTAMPREPLY:
    196      1.8.4.3     jdc 		case ICMP_IREQ:
    197      1.8.4.3     jdc 		case ICMP_IREQREPLY:
    198      1.8.4.3     jdc 			/* Should contain ICMP query ID. */
    199      1.8.4.3     jdc 			ic = &npc->npc_l4.icmp;
    200      1.8.4.3     jdc 			offby = offsetof(struct icmp, icmp_id);
    201      1.8.4.3     jdc 			if (nbuf_advfetch(&nbuf, &n_ptr, offby,
    202      1.8.4.3     jdc 			    sizeof(uint16_t), &ic->icmp_id)) {
    203      1.8.4.3     jdc 				return false;
    204      1.8.4.3     jdc 			}
    205      1.8.4.3     jdc 			npc->npc_info |= NPC_ICMP_ID;
    206      1.8.4.3     jdc 			return true;
    207          1.4   rmind 		default:
    208      1.8.4.3     jdc 			break;
    209          1.1   rmind 		}
    210      1.8.4.3     jdc 		/* No unique IDs. */
    211      1.8.4.3     jdc 		return false;
    212      1.8.4.3     jdc 	}
    213  1.8.4.3.2.1    matt 	if (npcinf & NPC_IP6) {
    214      1.8.4.3     jdc 		switch (type) {
    215      1.8.4.3     jdc 		/* Per RFC 4443. */
    216      1.8.4.3     jdc 		case ICMP6_DST_UNREACH:
    217      1.8.4.3     jdc 		case ICMP6_PACKET_TOO_BIG:
    218      1.8.4.3     jdc 		case ICMP6_TIME_EXCEEDED:
    219      1.8.4.3     jdc 		case ICMP6_PARAM_PROB:
    220      1.8.4.3     jdc 			/* Should contain original IP header. */
    221      1.8.4.3     jdc 			offby = sizeof(struct icmp6_hdr);
    222      1.8.4.3     jdc 			if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
    223      1.8.4.3     jdc 				return false;
    224      1.8.4.3     jdc 			}
    225      1.8.4.3     jdc 			/* Fetch into the cache. */
    226      1.8.4.3     jdc 			if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
    227      1.8.4.3     jdc 				return false;
    228      1.8.4.3     jdc 			}
    229      1.8.4.3     jdc 			switch (npf_cache_ipproto(npc)) {
    230      1.8.4.3     jdc 			case IPPROTO_TCP:
    231      1.8.4.3     jdc 				return npf_fetch_tcp(npc, nbuf, n_ptr);
    232      1.8.4.3     jdc 			case IPPROTO_UDP:
    233      1.8.4.3     jdc 				return npf_fetch_udp(npc, nbuf, n_ptr);
    234      1.8.4.3     jdc 			default:
    235      1.8.4.3     jdc 				return false;
    236      1.8.4.3     jdc 			}
    237      1.8.4.3     jdc 			return true;
    238      1.8.4.3     jdc 
    239      1.8.4.3     jdc 		case ICMP6_ECHO_REQUEST:
    240      1.8.4.3     jdc 		case ICMP6_ECHO_REPLY:
    241      1.8.4.3     jdc 			/* Should contain ICMP query ID. */
    242      1.8.4.3     jdc 			ic6 = &npc->npc_l4.icmp6;
    243      1.8.4.3     jdc 			offby = offsetof(struct icmp6_hdr, icmp6_id);
    244      1.8.4.3     jdc 			if (nbuf_advfetch(&nbuf, &n_ptr, offby,
    245      1.8.4.3     jdc 			    sizeof(uint16_t), &ic6->icmp6_id)) {
    246      1.8.4.3     jdc 				return false;
    247      1.8.4.3     jdc 			}
    248      1.8.4.3     jdc 			npc->npc_info |= NPC_ICMP_ID;
    249      1.8.4.3     jdc 			return true;
    250      1.8.4.3     jdc 		default:
    251      1.8.4.3     jdc 			break;
    252          1.1   rmind 		}
    253      1.8.4.3     jdc 		/* No unique IDs. */
    254      1.8.4.3     jdc 		return false;
    255          1.1   rmind 	}
    256      1.8.4.3     jdc 	/* Whatever protocol that may have been ... */
    257          1.1   rmind 	return false;
    258          1.1   rmind }
    259          1.1   rmind 
    260          1.6   rmind static void
    261          1.6   rmind npfa_srcdst_invert(npf_cache_t *npc)
    262          1.6   rmind {
    263          1.6   rmind 	const int proto = npf_cache_ipproto(npc);
    264          1.6   rmind 	npf_addr_t *tmp_ip;
    265          1.6   rmind 
    266          1.6   rmind 	if (proto == IPPROTO_TCP) {
    267          1.6   rmind 		struct tcphdr *th = &npc->npc_l4.tcp;
    268          1.6   rmind 		in_port_t tmp_sport = th->th_sport;
    269          1.6   rmind 		th->th_sport = th->th_dport;
    270          1.6   rmind 		th->th_dport = tmp_sport;
    271          1.6   rmind 
    272          1.6   rmind 	} else if (proto == IPPROTO_UDP) {
    273          1.6   rmind 		struct udphdr *uh = &npc->npc_l4.udp;
    274          1.6   rmind 		in_port_t tmp_sport = uh->uh_sport;
    275          1.6   rmind 		uh->uh_sport = uh->uh_dport;
    276          1.6   rmind 		uh->uh_dport = tmp_sport;
    277          1.6   rmind 	}
    278          1.6   rmind 	tmp_ip = npc->npc_srcip;
    279          1.6   rmind 	npc->npc_srcip = npc->npc_dstip;
    280          1.6   rmind 	npc->npc_dstip = tmp_ip;
    281          1.6   rmind }
    282          1.6   rmind 
    283          1.1   rmind /*
    284          1.6   rmind  * npfa_icmp_session: ALG session inspector, returns unique identifiers.
    285          1.1   rmind  */
    286          1.1   rmind static bool
    287          1.1   rmind npfa_icmp_session(npf_cache_t *npc, nbuf_t *nbuf, void *keyptr)
    288          1.1   rmind {
    289          1.1   rmind 	npf_cache_t *key = keyptr;
    290          1.6   rmind 	KASSERT(key->npc_info == 0);
    291          1.1   rmind 
    292          1.6   rmind 	/* IP + ICMP?  Get unique identifiers from ICMP packet. */
    293          1.6   rmind 	if (!npf_iscached(npc, NPC_IP4)) {
    294          1.6   rmind 		return false;
    295          1.6   rmind 	}
    296          1.4   rmind 	if (npf_cache_ipproto(npc) != IPPROTO_ICMP) {
    297          1.1   rmind 		return false;
    298          1.1   rmind 	}
    299          1.4   rmind 	KASSERT(npf_iscached(npc, NPC_ICMP));
    300          1.1   rmind 
    301          1.1   rmind 	/* Advance to ICMP header. */
    302          1.4   rmind 	void *n_ptr = nbuf_dataptr(nbuf);
    303          1.8   rmind 	const u_int hlen = npf_cache_hlen(npc);
    304          1.4   rmind 
    305          1.7  zoltan 	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, hlen)) == NULL) {
    306          1.1   rmind 		return false;
    307          1.1   rmind 	}
    308          1.1   rmind 
    309          1.4   rmind 	/* Fetch relevant data into the separate ("key") cache. */
    310          1.4   rmind 	struct icmp *ic = &npc->npc_l4.icmp;
    311  1.8.4.3.2.1    matt 	if (!npf_icmp_uniqid(npc->npc_info & NPC_IP46, ic->icmp_type,
    312  1.8.4.3.2.1    matt 	    key, nbuf, n_ptr)) {
    313          1.1   rmind 		return false;
    314          1.1   rmind 	}
    315          1.1   rmind 
    316          1.1   rmind 	if (npf_iscached(key, NPC_ICMP_ID)) {
    317          1.4   rmind 		struct icmp *keyic = &key->npc_l4.icmp;
    318          1.4   rmind 
    319          1.4   rmind 		/* Copy ICMP ID to the cache and flag it. */
    320          1.4   rmind 		npc->npc_info |= NPC_ICMP_ID;
    321          1.4   rmind 		ic->icmp_id = keyic->icmp_id;
    322          1.4   rmind 
    323          1.6   rmind 		/* Note: return False, since key is the original cache. */
    324          1.4   rmind 		return false;
    325          1.1   rmind 	}
    326          1.4   rmind 
    327          1.4   rmind 	/*
    328          1.4   rmind 	 * Embedded IP packet is the original of "forwards" stream.
    329          1.4   rmind 	 * We should imitate the "backwards" stream for inspection.
    330          1.4   rmind 	 */
    331          1.4   rmind 	KASSERT(npf_iscached(key, NPC_IP46));
    332          1.4   rmind 	KASSERT(npf_iscached(key, NPC_LAYER4));
    333          1.6   rmind 	npfa_srcdst_invert(key);
    334      1.8.4.2     riz 	key->npc_alen = npc->npc_alen;
    335          1.4   rmind 
    336          1.1   rmind 	return true;
    337          1.1   rmind }
    338          1.1   rmind 
    339          1.1   rmind /*
    340          1.1   rmind  * npfa_icmp_natin: ALG inbound translation inspector, rewrite IP address
    341          1.1   rmind  * in the IP header, which is embedded in ICMP packet.
    342          1.1   rmind  */
    343          1.1   rmind static bool
    344          1.1   rmind npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
    345          1.1   rmind {
    346          1.6   rmind 	npf_cache_t enpc = { .npc_info = 0 };
    347          1.1   rmind 
    348          1.6   rmind 	/* XXX: Duplicated work (done at session inspection). */
    349          1.1   rmind 	if (!npfa_icmp_session(npc, nbuf, &enpc)) {
    350          1.1   rmind 		return false;
    351          1.1   rmind 	}
    352          1.6   rmind 	/* XXX: Restore inversion (inefficient). */
    353          1.7  zoltan 	KASSERT(npf_iscached(&enpc, NPC_IP46));
    354          1.7  zoltan 	KASSERT(npf_iscached(&enpc, NPC_LAYER4));
    355          1.6   rmind 	npfa_srcdst_invert(&enpc);
    356          1.1   rmind 
    357          1.6   rmind 	/*
    358          1.6   rmind 	 * Save ICMP and embedded IP with TCP/UDP header checksums, retrieve
    359          1.6   rmind 	 * the original address and port, and calculate ICMP checksum for
    360          1.6   rmind 	 * embedded packet changes, while data is not rewritten in the cache.
    361          1.6   rmind 	 */
    362          1.4   rmind 	const int proto = npf_cache_ipproto(&enpc);
    363          1.7  zoltan 	const struct ip *eip = &enpc.npc_ip.v4;
    364          1.6   rmind 	const struct icmp * const ic = &npc->npc_l4.icmp;
    365          1.6   rmind 	uint16_t cksum = ic->icmp_cksum, ecksum = eip->ip_sum, l4cksum;
    366          1.6   rmind 	npf_nat_t *nt = ntptr;
    367          1.6   rmind 	npf_addr_t *addr;
    368          1.6   rmind 	in_port_t port;
    369          1.6   rmind 
    370          1.6   rmind 	npf_nat_getorig(nt, &addr, &port);
    371          1.4   rmind 
    372          1.4   rmind 	if (proto == IPPROTO_TCP) {
    373          1.4   rmind 		struct tcphdr *th = &enpc.npc_l4.tcp;
    374          1.6   rmind 		cksum = npf_fixup16_cksum(cksum, th->th_sport, port);
    375          1.4   rmind 		l4cksum = th->th_sum;
    376          1.4   rmind 	} else {
    377          1.4   rmind 		struct udphdr *uh = &enpc.npc_l4.udp;
    378          1.6   rmind 		cksum = npf_fixup16_cksum(cksum, uh->uh_sport, port);
    379          1.4   rmind 		l4cksum = uh->uh_sum;
    380          1.1   rmind 	}
    381      1.8.4.2     riz 	cksum = npf_addr_cksum(cksum, enpc.npc_alen, enpc.npc_srcip, addr);
    382          1.6   rmind 
    383          1.6   rmind 	/*
    384          1.6   rmind 	 * Save the original pointers to the main IP header and then advance
    385          1.6   rmind 	 * to the embedded IP header after ICMP header.
    386          1.6   rmind 	 */
    387          1.6   rmind 	void *n_ptr = nbuf_dataptr(nbuf), *cnbuf = nbuf, *cnptr = n_ptr;
    388          1.8   rmind 	u_int offby = npf_cache_hlen(npc) + offsetof(struct icmp, icmp_ip);
    389          1.1   rmind 
    390          1.1   rmind 	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
    391          1.1   rmind 		return false;
    392          1.1   rmind 	}
    393          1.1   rmind 
    394          1.4   rmind 	/*
    395          1.4   rmind 	 * Rewrite source IP address and port of the embedded IP header,
    396          1.4   rmind 	 * which represents original packet - therefore passing PFIL_OUT.
    397          1.6   rmind 	 * Note: checksums are first, since it uses values from the cache.
    398          1.4   rmind 	 */
    399          1.4   rmind 	if (!npf_rwrcksum(&enpc, nbuf, n_ptr, PFIL_OUT, addr, port)) {
    400          1.4   rmind 		return false;
    401          1.4   rmind 	}
    402          1.1   rmind 	if (!npf_rwrip(&enpc, nbuf, n_ptr, PFIL_OUT, addr)) {
    403          1.1   rmind 		return false;
    404          1.1   rmind 	}
    405          1.4   rmind 	if (!npf_rwrport(&enpc, nbuf, n_ptr, PFIL_OUT, port)) {
    406          1.1   rmind 		return false;
    407          1.1   rmind 	}
    408          1.1   rmind 
    409          1.1   rmind 	/*
    410          1.6   rmind 	 * Finish calculation of the ICMP checksum.  Update for embedded IP
    411          1.6   rmind 	 * and TCP/UDP checksum changes.  Finally, rewrite ICMP checksum.
    412          1.1   rmind 	 */
    413          1.4   rmind 	if (proto == IPPROTO_TCP) {
    414          1.4   rmind 		struct tcphdr *th = &enpc.npc_l4.tcp;
    415          1.4   rmind 		cksum = npf_fixup16_cksum(cksum, l4cksum, th->th_sum);
    416          1.6   rmind 	} else if (l4cksum) {
    417          1.4   rmind 		struct udphdr *uh = &enpc.npc_l4.udp;
    418          1.4   rmind 		cksum = npf_fixup16_cksum(cksum, l4cksum, uh->uh_sum);
    419          1.1   rmind 	}
    420          1.6   rmind 	cksum = npf_fixup16_cksum(cksum, ecksum, eip->ip_sum);
    421          1.4   rmind 
    422          1.8   rmind 	offby = npf_cache_hlen(npc) + offsetof(struct icmp, icmp_cksum);
    423          1.6   rmind 	if (nbuf_advstore(&cnbuf, &cnptr, offby, sizeof(uint16_t), &cksum)) {
    424          1.6   rmind 		return false;
    425          1.6   rmind 	}
    426          1.6   rmind 	return true;
    427          1.1   rmind }
    428