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
59VNET_DECLARE(ipf_main_softc_t, ipfmain);
60#define	V_ipfmain		VNET(ipfmain)
61
62
63static u_long in_rule__0[] = {
640, 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
67static u_long out_rule__0[] = {
680, 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
71frentry_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	*/
82frentry_t *ipf_rules_out_[1] = {
83	(frentry_t *)&out_rule__0
84};
85
86frentry_t *ipfrule_match_in_(fin, passp)
87fr_info_t *fin;
88u_32_t *passp;
89{
90	frentry_t *fr = NULL;
91
92	fr = (frentry_t *)&in_rule__0;
93	return fr;
94}
95
96frentry_t *ipfrule_match_out_(fin, passp)
97fr_info_t *fin;
98u_32_t *passp;
99{
100	frentry_t *fr = NULL;
101
102	fr = (frentry_t *)&out_rule__0;
103	return fr;
104}
105static frentry_t ipfrule_out_;
106
107int ipfrule_add_out_()
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
144int ipfrule_remove_out_()
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}
174static frentry_t ipfrule_in_;
175
176int ipfrule_add_in_()
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
213int ipfrule_remove_in_()
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
244int ipfrule_add()
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
258int ipfrule_remove()
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