1 /*	$FreeBSD$	*/
2 
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and due credit is given
8 * to the original author and the contributors.
9 */
10 
11 #include <sys/param.h>
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <sys/socket.h>
15 #if defined(__FreeBSD__)
16 # if defined(_KERNEL)
17 #  include <sys/libkern.h>
18 # else
19 #  include <sys/unistd.h>
20 # endif
21 #else
22 # include <sys/systm.h>
23 #endif
24 #include <sys/errno.h>
25 #include <sys/param.h>
26 #if !defined(__SVR4)
27 # include <sys/mbuf.h>
28 #endif
29 #if defined(__FreeBSD__)
30 # include <sys/sockio.h>
31 #if defined(_KERNEL)
32 #include <net/vnet.h>
33 #else
34 #define CURVNET_SET(arg)
35 #define CURVNET_RESTORE()
36 #define	VNET_DEFINE(_t, _v)	_t _v
37 #define	VNET_DECLARE(_t, _v)	extern _t _v
38 #define	VNET(arg)	arg
39 #endif
40 #else
41 # include <sys/ioctl.h>
42 #endif /* FreeBSD */
43 #include <net/if.h>
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <netinet/tcp.h>
48 #include "netinet/ip_compat.h"
49 #include "netinet/ip_fil.h"
50 
51 #include "netinet/ip_rules.h"
52 
53 #ifndef _KERNEL
54 # include <string.h>
55 #endif /* _KERNEL */
56 
57 #ifdef IPFILTER_COMPILED
58 
59 VNET_DECLARE(ipf_main_softc_t, ipfmain);
60 #define	V_ipfmain		VNET(ipfmain)
61 
62 
63 static u_long in_rule__0[] = {
64 0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x8002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
65 };
66 
67 static u_long out_rule__0[] = {
68 0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x4002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
69 };
70 
71 frentry_t *ipf_rules_in_[1] = {
72 	(frentry_t *)&in_rule__0
73 };
74 
75 /* XXX	This file (ip_rules.c) is not part of the ipfilter tarball, it is
76    XXX	generated by the ipfilter build process. Unfortunately the build
77    XXX  process did not generate the following lines so they are added
78    XXX	by hand here. This is a bit of a hack but it works for now. Future
79    XXX  imports/merges of ipfilter may generate this so the following will
80    XXX	need to be removed following some future merge.
81    XXX	*/
82 frentry_t *ipf_rules_out_[1] = {
83 	(frentry_t *)&out_rule__0
84 };
85 
86 frentry_t *ipfrule_match_in_(fin, passp)
87 fr_info_t *fin;
88 u_32_t *passp;
89 {
90 	frentry_t *fr = NULL;
91 
92 	fr = (frentry_t *)&in_rule__0;
93 	return (fr);
94 }
95 
96 frentry_t *ipfrule_match_out_(fin, passp)
97 fr_info_t *fin;
98 u_32_t *passp;
99 {
100 	frentry_t *fr = NULL;
101 
102 	fr = (frentry_t *)&out_rule__0;
103 	return (fr);
104 }
105 static frentry_t ipfrule_out_;
106 
107 int ipfrule_add_out_(void)
108 {
109 	int i, j, err = 0, max;
110 	frentry_t *fp;
111 
112 	max = sizeof(ipf_rules_out_)/sizeof(frentry_t *);
113 	for (i = 0; i < max; i++) {
114 		fp = ipf_rules_out_[i];
115 		fp->fr_next = NULL;
116 		for (j = i + 1; j < max; j++)
117 			if (strncmp(fp->fr_names + fp->fr_group,
118 				    ipf_rules_out_[j]->fr_names +
119 				    ipf_rules_out_[j]->fr_group,
120 				    FR_GROUPLEN) == 0) {
121 				if (ipf_rules_out_[j] != NULL)
122 					ipf_rules_out_[j]->fr_pnext =
123 					    &fp->fr_next;
124 				fp->fr_pnext = &ipf_rules_out_[j];
125 				fp->fr_next = ipf_rules_out_[j];
126 				break;
127 			}
128 	}
129 
130 	fp = &ipfrule_out_;
131 	bzero((char *)fp, sizeof(*fp));
132 	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
133 	fp->fr_flags = FR_OUTQUE|FR_NOMATCH;
134 	fp->fr_data = (void *)ipf_rules_out_[0];
135 	fp->fr_dsize = sizeof(ipf_rules_out_[0]);
136 	fp->fr_family = AF_INET;
137 	fp->fr_func = (ipfunc_t)ipfrule_match_out_;
138 	err = frrequest(&V_ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
139 			V_ipfmain.ipf_active, 0);
140 	return (err);
141 }
142 
143 
144 int ipfrule_remove_out_(void)
145 {
146 	int err = 0, i;
147 	frentry_t *fp;
148 
149 	/*
150 	 * Try to remove the outbound rule.
151 	 */
152 	if (ipfrule_out_.fr_ref > 0) {
153 		err = EBUSY;
154 	} else {
155 		i = sizeof(ipf_rules_out_)/sizeof(frentry_t *) - 1;
156 		for (; i >= 0; i--) {
157 			fp = ipf_rules_out_[i];
158 			if (fp->fr_ref > 1) {
159 				err = EBUSY;
160 				break;
161 			}
162 		}
163 	}
164 	if (err == 0)
165 		err = frrequest(&V_ipfmain, IPL_LOGIPF, SIOCDELFR,
166 				(caddr_t)&ipfrule_out_,
167 				V_ipfmain.ipf_active, 0);
168 	if (err)
169 		return (err);
170 
171 
172 	return (err);
173 }
174 static frentry_t ipfrule_in_;
175 
176 int ipfrule_add_in_(void)
177 {
178 	int i, j, err = 0, max;
179 	frentry_t *fp;
180 
181 	max = sizeof(ipf_rules_in_)/sizeof(frentry_t *);
182 	for (i = 0; i < max; i++) {
183 		fp = ipf_rules_in_[i];
184 		fp->fr_next = NULL;
185 		for (j = i + 1; j < max; j++)
186 			if (strncmp(fp->fr_names + fp->fr_group,
187 				    ipf_rules_in_[j]->fr_names +
188 				    ipf_rules_in_[j]->fr_group,
189 				    FR_GROUPLEN) == 0) {
190 				if (ipf_rules_in_[j] != NULL)
191 					ipf_rules_in_[j]->fr_pnext =
192 					    &fp->fr_next;
193 				fp->fr_pnext = &ipf_rules_in_[j];
194 				fp->fr_next = ipf_rules_in_[j];
195 				break;
196 			}
197 	}
198 
199 	fp = &ipfrule_in_;
200 	bzero((char *)fp, sizeof(*fp));
201 	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
202 	fp->fr_flags = FR_INQUE|FR_NOMATCH;
203 	fp->fr_data = (void *)ipf_rules_in_[0];
204 	fp->fr_dsize = sizeof(ipf_rules_in_[0]);
205 	fp->fr_family = AF_INET;
206 	fp->fr_func = (ipfunc_t)ipfrule_match_in_;
207 	err = frrequest(&V_ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
208 			V_ipfmain.ipf_active, 0);
209 	return (err);
210 }
211 
212 
213 int ipfrule_remove_in_(void)
214 {
215 	int err = 0, i;
216 	frentry_t *fp;
217 
218 	/*
219 	 * Try to remove the inbound rule.
220 	 */
221 	if (ipfrule_in_.fr_ref > 0) {
222 		err = EBUSY;
223 	} else {
224 		i = sizeof(ipf_rules_in_)/sizeof(frentry_t *) - 1;
225 		for (; i >= 0; i--) {
226 			fp = ipf_rules_in_[i];
227 			if (fp->fr_ref > 1) {
228 				err = EBUSY;
229 				break;
230 			}
231 		}
232 	}
233 	if (err == 0)
234 		err = frrequest(&V_ipfmain, IPL_LOGIPF, SIOCDELFR,
235 				(caddr_t)&ipfrule_in_,
236 				V_ipfmain.ipf_active, 0);
237 	if (err)
238 		return (err);
239 
240 
241 	return (err);
242 }
243 
244 int ipfrule_add(void)
245 {
246 	int err;
247 
248 	err = ipfrule_add_out_();
249 	if (err != 0)
250 		return (err);
251 	err = ipfrule_add_in_();
252 	if (err != 0)
253 		return (err);
254 	return (0);
255 }
256 
257 
258 int ipfrule_remove(void)
259 {
260 	int err;
261 
262 	err = ipfrule_remove_out_();
263 	if (err != 0)
264 		return (err);
265 	err = ipfrule_remove_in_();
266 	if (err != 0)
267 		return (err);
268 	return (0);
269 }
270 #endif /* IPFILTER_COMPILED */
271