xref: /netbsd-src/sys/net/npf/npf_sendpkt.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: npf_sendpkt.c,v 1.4 2011/01/18 20:33:46 rmind Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This material is based upon work partially supported by The
8  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * NPF module for packet construction routines.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.4 2011/01/18 20:33:46 rmind Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 
42 #include <netinet/in_systm.h>
43 #include <netinet/in.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip_icmp.h>
46 #include <netinet/ip_var.h>
47 #include <netinet/tcp.h>
48 #include <sys/mbuf.h>
49 
50 #include "npf_impl.h"
51 
52 #define	DEFAULT_IP_TTL		(ip_defttl)
53 
54 /*
55  * npf_return_tcp: return a TCP reset (RST) packet.
56  */
57 static int
58 npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
59 {
60 	struct mbuf *m;
61 	struct ip *oip, *ip;
62 	struct tcphdr *oth, *th;
63 	tcp_seq seq, ack;
64 	int tcpdlen, len;
65 	uint32_t win;
66 
67 	/* Fetch relevant data. */
68 	KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
69 	tcpdlen = npf_tcpsaw(npc, &seq, &ack, &win);
70 	oip = &npc->npc_ip.v4;
71 	oth = &npc->npc_l4.tcp;
72 
73 	if (oth->th_flags & TH_RST) {
74 		return 0;
75 	}
76 
77 	/* Create and setup a network buffer. */
78 	len = sizeof(struct ip) + sizeof(struct tcphdr);
79 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
80 	if (m == NULL) {
81 		return ENOMEM;
82 	}
83 	m->m_data += max_linkhdr;
84 	m->m_len = len;
85 	m->m_pkthdr.len = len;
86 
87 	ip = mtod(m, struct ip *);
88 	memset(ip, 0, len);
89 
90 	/*
91 	 * First fill of IPv4 header, for TCP checksum.
92 	 * Note: IP length contains TCP header length.
93 	 */
94 	ip->ip_p = IPPROTO_TCP;
95 	ip->ip_src.s_addr = oip->ip_dst.s_addr;
96 	ip->ip_dst.s_addr = oip->ip_src.s_addr;
97 	ip->ip_len = htons(sizeof(struct tcphdr));
98 
99 	/* Construct TCP header and compute the checksum. */
100 	th = (struct tcphdr *)(ip + 1);
101 	th->th_sport = oth->th_dport;
102 	th->th_dport = oth->th_sport;
103 	th->th_seq = htonl(ack);
104 	if (oth->th_flags & TH_SYN) {
105 		tcpdlen++;
106 	}
107 	th->th_ack = htonl(seq + tcpdlen);
108 	th->th_off = sizeof(struct tcphdr) >> 2;
109 	th->th_flags = TH_ACK | TH_RST;
110 	th->th_sum = in_cksum(m, len);
111 
112 	/* Second fill of IPv4 header, fill correct IP length. */
113 	ip->ip_v = IPVERSION;
114 	ip->ip_hl = sizeof(struct ip) >> 2;
115 	ip->ip_tos = IPTOS_LOWDELAY;
116 	ip->ip_len = htons(len);
117 	ip->ip_ttl = DEFAULT_IP_TTL;
118 
119 	/* Pass to IP layer. */
120 	return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
121 }
122 
123 /*
124  * npf_return_icmp: return an ICMP error.
125  */
126 static int
127 npf_return_icmp(nbuf_t *nbuf)
128 {
129 	struct mbuf *m = nbuf;
130 
131 	icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
132 	return 0;
133 }
134 
135 /*
136  * npf_return_block: return TCP reset or ICMP host unreachable packet.
137  */
138 void
139 npf_return_block(npf_cache_t *npc, nbuf_t *nbuf, const int retfl)
140 {
141 	void *n_ptr = nbuf_dataptr(nbuf);
142 
143 	if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
144 		return;
145 	}
146 	switch (npf_cache_ipproto(npc)) {
147 	case IPPROTO_TCP:
148 		if (retfl & NPF_RULE_RETRST) {
149 			if (!npf_fetch_tcp(npc, nbuf, n_ptr)) {
150 				return;
151 			}
152 			(void)npf_return_tcp(npc, nbuf);
153 		}
154 		break;
155 	case IPPROTO_UDP:
156 		if (retfl & NPF_RULE_RETICMP) {
157 			(void)npf_return_icmp(nbuf);
158 		}
159 		break;
160 	}
161 }
162