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