1145516Sdarrenr/*	$FreeBSD$	*/
2145516Sdarrenr
3145516Sdarrenr/*
4255332Scy* Copyright (C) 2012 by Darren Reed.
5145516Sdarrenr*
6145516Sdarrenr* Redistribution and use in source and binary forms are permitted
7145516Sdarrenr* provided that this notice is preserved and due credit is given
8145516Sdarrenr* to the original author and the contributors.
9145516Sdarrenr*/
10145516Sdarrenr
11255332Scy#include <sys/param.h>
12145516Sdarrenr#include <sys/types.h>
13145516Sdarrenr#include <sys/time.h>
14145516Sdarrenr#include <sys/socket.h>
15255332Scy#if defined(__FreeBSD_version) && (__FreeBSD_version >= 40000)
16255332Scy# if defined(_KERNEL)
17255332Scy#  include <sys/libkern.h>
18255332Scy# else
19255332Scy#  include <sys/unistd.h>
20255332Scy# endif
21145516Sdarrenr#endif
22255332Scy#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399000000)
23255332Scy#else
24255332Scy# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
25255332Scy#  include <sys/systm.h>
26255332Scy# endif
27255332Scy#endif
28145516Sdarrenr#include <sys/errno.h>
29145516Sdarrenr#include <sys/param.h>
30145516Sdarrenr#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)
31145516Sdarrenr# include <sys/mbuf.h>
32145516Sdarrenr#endif
33145516Sdarrenr#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)
34145516Sdarrenr# include <sys/sockio.h>
35145516Sdarrenr#else
36145516Sdarrenr# include <sys/ioctl.h>
37145516Sdarrenr#endif /* FreeBSD */
38145516Sdarrenr#include <net/if.h>
39145516Sdarrenr#include <netinet/in.h>
40145516Sdarrenr#include <netinet/in_systm.h>
41145516Sdarrenr#include <netinet/ip.h>
42145516Sdarrenr#include <netinet/tcp.h>
43145516Sdarrenr#include "netinet/ip_compat.h"
44145516Sdarrenr#include "netinet/ip_fil.h"
45145516Sdarrenr
46145516Sdarrenr#include "netinet/ip_rules.h"
47145516Sdarrenr
48145516Sdarrenr#ifndef _KERNEL
49145516Sdarrenr# include <string.h>
50145516Sdarrenr#endif /* _KERNEL */
51145516Sdarrenr
52145516Sdarrenr#ifdef IPFILTER_COMPILED
53145516Sdarrenr
54255332Scyextern ipf_main_softc_t ipfmain;
55255332Scy
56255332Scy
57145516Sdarrenrstatic u_long in_rule__0[] = {
58255332Scy0, 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
59145516Sdarrenr};
60145516Sdarrenr
61145516Sdarrenrstatic u_long out_rule__0[] = {
62255332Scy0, 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
63145516Sdarrenr};
64145516Sdarrenr
65145516Sdarrenrfrentry_t *ipf_rules_in_[1] = {
66145516Sdarrenr	(frentry_t *)&in_rule__0
67145516Sdarrenr};
68145516Sdarrenr
69255332Scy/* XXX	This file (ip_rules.c) is not part of the ipfilter tarball, it is
70255332Scy   XXX	generated by the ipfilter build process. Unfortunately the build
71255332Scy   XXX  process did not generate the following lines so they are added
72255332Scy   XXX	by hand here. This is a bit of a hack but it works for now. Future
73255332Scy   XXX  imports/merges of ipfilter may generate this so the following will
74255332Scy   XXX	need to be removed following some future merge.
75255332Scy   XXX	*/
76255332Scyfrentry_t *ipf_rules_out_[1] = {
77255332Scy	(frentry_t *)&out_rule__0
78255332Scy};
79255332Scy
80145516Sdarrenrfrentry_t *ipfrule_match_in_(fin, passp)
81145516Sdarrenrfr_info_t *fin;
82145516Sdarrenru_32_t *passp;
83145516Sdarrenr{
84145516Sdarrenr	frentry_t *fr = NULL;
85145516Sdarrenr
86145516Sdarrenr	fr = (frentry_t *)&in_rule__0;
87145516Sdarrenr	return fr;
88145516Sdarrenr}
89145516Sdarrenr
90145516Sdarrenrfrentry_t *ipfrule_match_out_(fin, passp)
91145516Sdarrenrfr_info_t *fin;
92145516Sdarrenru_32_t *passp;
93145516Sdarrenr{
94145516Sdarrenr	frentry_t *fr = NULL;
95145516Sdarrenr
96145516Sdarrenr	fr = (frentry_t *)&out_rule__0;
97145516Sdarrenr	return fr;
98145516Sdarrenr}
99145516Sdarrenrstatic frentry_t ipfrule_out_;
100145516Sdarrenr
101145516Sdarrenrint ipfrule_add_out_()
102145516Sdarrenr{
103145516Sdarrenr	int i, j, err = 0, max;
104145516Sdarrenr	frentry_t *fp;
105145516Sdarrenr
106145516Sdarrenr	max = sizeof(ipf_rules_out_)/sizeof(frentry_t *);
107145516Sdarrenr	for (i = 0; i < max; i++) {
108145516Sdarrenr		fp = ipf_rules_out_[i];
109145516Sdarrenr		fp->fr_next = NULL;
110145516Sdarrenr		for (j = i + 1; j < max; j++)
111255332Scy			if (strncmp(fp->fr_names + fp->fr_group,
112255332Scy				    ipf_rules_out_[j]->fr_names +
113145516Sdarrenr				    ipf_rules_out_[j]->fr_group,
114145516Sdarrenr				    FR_GROUPLEN) == 0) {
115255332Scy				if (ipf_rules_out_[j] != NULL)
116255332Scy					ipf_rules_out_[j]->fr_pnext =
117255332Scy					    &fp->fr_next;
118255332Scy				fp->fr_pnext = &ipf_rules_out_[j];
119145516Sdarrenr				fp->fr_next = ipf_rules_out_[j];
120145516Sdarrenr				break;
121145516Sdarrenr			}
122145516Sdarrenr	}
123145516Sdarrenr
124145516Sdarrenr	fp = &ipfrule_out_;
125145516Sdarrenr	bzero((char *)fp, sizeof(*fp));
126255332Scy	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
127145516Sdarrenr	fp->fr_flags = FR_OUTQUE|FR_NOMATCH;
128145516Sdarrenr	fp->fr_data = (void *)ipf_rules_out_[0];
129145516Sdarrenr	fp->fr_dsize = sizeof(ipf_rules_out_[0]);
130255332Scy	fp->fr_family = AF_INET;
131145516Sdarrenr	fp->fr_func = (ipfunc_t)ipfrule_match_out_;
132255332Scy	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
133255332Scy			ipfmain.ipf_active, 0);
134145516Sdarrenr	return err;
135145516Sdarrenr}
136145516Sdarrenr
137145516Sdarrenr
138145516Sdarrenrint ipfrule_remove_out_()
139145516Sdarrenr{
140145516Sdarrenr	int err = 0, i;
141145516Sdarrenr	frentry_t *fp;
142145516Sdarrenr
143145516Sdarrenr	/*
144145516Sdarrenr	 * Try to remove the outbound rule.
145145516Sdarrenr	 */
146145516Sdarrenr	if (ipfrule_out_.fr_ref > 0) {
147145516Sdarrenr		err = EBUSY;
148145516Sdarrenr	} else {
149145516Sdarrenr		i = sizeof(ipf_rules_out_)/sizeof(frentry_t *) - 1;
150145516Sdarrenr		for (; i >= 0; i--) {
151145516Sdarrenr			fp = ipf_rules_out_[i];
152145516Sdarrenr			if (fp->fr_ref > 1) {
153145516Sdarrenr				err = EBUSY;
154145516Sdarrenr				break;
155145516Sdarrenr			}
156145516Sdarrenr		}
157145516Sdarrenr	}
158145516Sdarrenr	if (err == 0)
159255332Scy		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
160255332Scy				(caddr_t)&ipfrule_out_,
161255332Scy				ipfmain.ipf_active, 0);
162145516Sdarrenr	if (err)
163145516Sdarrenr		return err;
164145516Sdarrenr
165145516Sdarrenr
166145516Sdarrenr	return err;
167145516Sdarrenr}
168145516Sdarrenrstatic frentry_t ipfrule_in_;
169145516Sdarrenr
170145516Sdarrenrint ipfrule_add_in_()
171145516Sdarrenr{
172145516Sdarrenr	int i, j, err = 0, max;
173145516Sdarrenr	frentry_t *fp;
174145516Sdarrenr
175145516Sdarrenr	max = sizeof(ipf_rules_in_)/sizeof(frentry_t *);
176145516Sdarrenr	for (i = 0; i < max; i++) {
177145516Sdarrenr		fp = ipf_rules_in_[i];
178145516Sdarrenr		fp->fr_next = NULL;
179145516Sdarrenr		for (j = i + 1; j < max; j++)
180255332Scy			if (strncmp(fp->fr_names + fp->fr_group,
181255332Scy				    ipf_rules_in_[j]->fr_names +
182145516Sdarrenr				    ipf_rules_in_[j]->fr_group,
183145516Sdarrenr				    FR_GROUPLEN) == 0) {
184255332Scy				if (ipf_rules_in_[j] != NULL)
185255332Scy					ipf_rules_in_[j]->fr_pnext =
186255332Scy					    &fp->fr_next;
187255332Scy				fp->fr_pnext = &ipf_rules_in_[j];
188145516Sdarrenr				fp->fr_next = ipf_rules_in_[j];
189145516Sdarrenr				break;
190145516Sdarrenr			}
191145516Sdarrenr	}
192145516Sdarrenr
193145516Sdarrenr	fp = &ipfrule_in_;
194145516Sdarrenr	bzero((char *)fp, sizeof(*fp));
195255332Scy	fp->fr_type = FR_T_CALLFUNC_BUILTIN;
196145516Sdarrenr	fp->fr_flags = FR_INQUE|FR_NOMATCH;
197145516Sdarrenr	fp->fr_data = (void *)ipf_rules_in_[0];
198145516Sdarrenr	fp->fr_dsize = sizeof(ipf_rules_in_[0]);
199255332Scy	fp->fr_family = AF_INET;
200145516Sdarrenr	fp->fr_func = (ipfunc_t)ipfrule_match_in_;
201255332Scy	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
202255332Scy			ipfmain.ipf_active, 0);
203145516Sdarrenr	return err;
204145516Sdarrenr}
205145516Sdarrenr
206145516Sdarrenr
207145516Sdarrenrint ipfrule_remove_in_()
208145516Sdarrenr{
209145516Sdarrenr	int err = 0, i;
210145516Sdarrenr	frentry_t *fp;
211145516Sdarrenr
212145516Sdarrenr	/*
213145516Sdarrenr	 * Try to remove the inbound rule.
214145516Sdarrenr	 */
215145516Sdarrenr	if (ipfrule_in_.fr_ref > 0) {
216145516Sdarrenr		err = EBUSY;
217145516Sdarrenr	} else {
218145516Sdarrenr		i = sizeof(ipf_rules_in_)/sizeof(frentry_t *) - 1;
219145516Sdarrenr		for (; i >= 0; i--) {
220145516Sdarrenr			fp = ipf_rules_in_[i];
221145516Sdarrenr			if (fp->fr_ref > 1) {
222145516Sdarrenr				err = EBUSY;
223145516Sdarrenr				break;
224145516Sdarrenr			}
225145516Sdarrenr		}
226145516Sdarrenr	}
227145516Sdarrenr	if (err == 0)
228255332Scy		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
229255332Scy				(caddr_t)&ipfrule_in_,
230255332Scy				ipfmain.ipf_active, 0);
231145516Sdarrenr	if (err)
232145516Sdarrenr		return err;
233145516Sdarrenr
234145516Sdarrenr
235145516Sdarrenr	return err;
236145516Sdarrenr}
237145516Sdarrenr
238145516Sdarrenrint ipfrule_add()
239145516Sdarrenr{
240145516Sdarrenr	int err;
241145516Sdarrenr
242145516Sdarrenr	err = ipfrule_add_out_();
243145516Sdarrenr	if (err != 0)
244145516Sdarrenr		return err;
245145516Sdarrenr	err = ipfrule_add_in_();
246145516Sdarrenr	if (err != 0)
247145516Sdarrenr		return err;
248145516Sdarrenr	return 0;
249145516Sdarrenr}
250145516Sdarrenr
251145516Sdarrenr
252145516Sdarrenrint ipfrule_remove()
253145516Sdarrenr{
254145516Sdarrenr	int err;
255145516Sdarrenr
256145516Sdarrenr	err = ipfrule_remove_out_();
257145516Sdarrenr	if (err != 0)
258145516Sdarrenr		return err;
259145516Sdarrenr	err = ipfrule_remove_in_();
260145516Sdarrenr	if (err != 0)
261145516Sdarrenr		return err;
262145516Sdarrenr	return 0;
263145516Sdarrenr}
264145516Sdarrenr#endif /* IPFILTER_COMPILED */
265