libipt_ULOG.c revision 4008138e2b5248940265b160fae001d8954fae21
11e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o/* Shared library add-on to iptables to add ULOG support.
21e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o *
319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * (C) 2000 by Harald Welte <laforge@gnumonks.org>
419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * multipart netlink support based on ideas by Sebastian Zander
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 						<zander@fokus.gmd.de>
73030daa8aba89830fb0623be01e507bffd636399Theodore Ts'o *
83030daa8aba89830fb0623be01e507bffd636399Theodore Ts'o * This software is released under the terms of GNU GPL
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
101e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o * libipt_ULOG.c,v 1.7 2001/01/30 11:55:02 laforge Exp
111e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o */
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include <stdio.h>
131e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o#include <netdb.h>
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o#include <string.h>
15b1416db3227b4b7192ee0d2d3ff6e00e92e9d3e2Theodore Ts'o#include <stdlib.h>
161e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o#include <syslog.h>
171e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o#include <getopt.h>
181e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o#include <iptables.h>
19ce2722f86de298ad1a8965f55a453b5723d2b2b9Theodore Ts'o#include <linux/netfilter_ipv4/ip_tables.h>
201e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o/* For 64bit kernel / 32bit userspace */
21ce2722f86de298ad1a8965f55a453b5723d2b2b9Theodore Ts'o#include "../include/linux/netfilter_ipv4/ipt_ULOG.h"
22ce2722f86de298ad1a8965f55a453b5723d2b2b9Theodore Ts'o
23ce2722f86de298ad1a8965f55a453b5723d2b2b9Theodore Ts'o
24ce2722f86de298ad1a8965f55a453b5723d2b2b9Theodore Ts'ovoid print_groups(unsigned int gmask)
251e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o{
261e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	int b;
271e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	unsigned int test;
281e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
291e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	for (b = 31; b >= 0; b--) {
301e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		test = (1 << b);
311e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		if (gmask & test)
321e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o			printf("%d ", b + 1);
331e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	}
341e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o}
351e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
361e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o/* Function which prints out usage message. */
371e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'ostatic void help(void)
381e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o{
391e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	printf("ULOG v%s options:\n"
401e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	       " --ulog-nlgroup nlgroup		NETLINK group used for logging\n"
411e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	       " --ulog-cprange size		Bytes of each packet to be passed\n"
421e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	       " --ulog-qthreshold		Threshold of in-kernel queue\n"
431e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	       " --ulog-prefix prefix		Prefix log messages with this prefix.\n\n",
441e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	       IPTABLES_VERSION);
451e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o}
461e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
471e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'ostatic struct option opts[] = {
481e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	{"ulog-nlgroup", 1, 0, '!'},
491e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	{"ulog-prefix", 1, 0, '#'},
501e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	{"ulog-cprange", 1, 0, 'A'},
511e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	{"ulog-qthreshold", 1, 0, 'B'},
521e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	{0}
531e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o};
54
55/* Initialize the target. */
56static void init(struct ipt_entry_target *t, unsigned int *nfcache)
57{
58	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) t->data;
59
60	loginfo->nl_group = ULOG_DEFAULT_NLGROUP;
61	loginfo->qthreshold = ULOG_DEFAULT_QTHRESHOLD;
62
63}
64
65#define IPT_LOG_OPT_NLGROUP 0x01
66#define IPT_LOG_OPT_PREFIX 0x02
67#define IPT_LOG_OPT_CPRANGE 0x04
68#define IPT_LOG_OPT_QTHRESHOLD 0x08
69
70/* Function which parses command options; returns true if it
71   ate an option */
72static int parse(int c, char **argv, int invert, unsigned int *flags,
73		 const struct ipt_entry *entry,
74		 struct ipt_entry_target **target)
75{
76	struct ipt_ulog_info *loginfo =
77	    (struct ipt_ulog_info *) (*target)->data;
78	int group_d;
79
80	switch (c) {
81	case '!':
82		if (*flags & IPT_LOG_OPT_NLGROUP)
83			exit_error(PARAMETER_PROBLEM,
84				   "Can't specify --ulog-nlgroup twice");
85
86		if (check_inverse(optarg, &invert, NULL, 0))
87			exit_error(PARAMETER_PROBLEM,
88				   "Unexpected `!' after --ulog-nlgroup");
89		group_d = atoi(optarg);
90		if (group_d > 32 || group_d < 1)
91			exit_error(PARAMETER_PROBLEM,
92				   "--ulog-nlgroup has to be between 1 and 32");
93
94		loginfo->nl_group = (1 << (group_d - 1));
95
96		*flags |= IPT_LOG_OPT_NLGROUP;
97		break;
98
99	case '#':
100		if (*flags & IPT_LOG_OPT_PREFIX)
101			exit_error(PARAMETER_PROBLEM,
102				   "Can't specify --ulog-prefix twice");
103
104		if (check_inverse(optarg, &invert, NULL, 0))
105			exit_error(PARAMETER_PROBLEM,
106				   "Unexpected `!' after --ulog-prefix");
107
108		if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
109			exit_error(PARAMETER_PROBLEM,
110				   "Maximum prefix length %u for --ulog-prefix",
111				   (unsigned int)sizeof(loginfo->prefix) - 1);
112
113		if (strlen(optarg) == 0)
114			exit_error(PARAMETER_PROBLEM,
115				   "No prefix specified for --ulog-prefix");
116
117		if (strlen(optarg) != strlen(strtok(optarg, "\n")))
118			exit_error(PARAMETER_PROBLEM,
119				   "Newlines not allowed in --ulog-prefix");
120
121		strcpy(loginfo->prefix, optarg);
122		*flags |= IPT_LOG_OPT_PREFIX;
123		break;
124	case 'A':
125		if (*flags & IPT_LOG_OPT_CPRANGE)
126			exit_error(PARAMETER_PROBLEM,
127				   "Can't specify --ulog-cprange twice");
128		if (atoi(optarg) < 0)
129			exit_error(PARAMETER_PROBLEM,
130				   "Negative copy range?");
131#ifdef KERNEL_64_USERSPACE_32
132		loginfo->copy_range = (unsigned long long)atoll(optarg);
133#else
134		loginfo->copy_range = atoi(optarg);
135#endif
136		*flags |= IPT_LOG_OPT_CPRANGE;
137		break;
138	case 'B':
139		if (*flags & IPT_LOG_OPT_QTHRESHOLD)
140			exit_error(PARAMETER_PROBLEM,
141				   "Can't specify --ulog-qthreshold twice");
142		if (atoi(optarg) < 1)
143			exit_error(PARAMETER_PROBLEM,
144				   "Negative or zero queue threshold ?");
145		if (atoi(optarg) > ULOG_MAX_QLEN)
146			exit_error(PARAMETER_PROBLEM,
147				   "Maximum queue length exceeded");
148#ifdef KERNEL_64_USERSPACE_32
149		loginfo->qthreshold = (unsigned long long)atoll(optarg);
150#else
151		loginfo->qthreshold = atoi(optarg);
152#endif
153		*flags |= IPT_LOG_OPT_QTHRESHOLD;
154		break;
155	default:
156		return 0;
157	}
158	return 1;
159}
160
161/* Final check; nothing. */
162static void final_check(unsigned int flags)
163{
164}
165
166/* Saves the union ipt_targinfo in parsable form to stdout. */
167static void save(const struct ipt_ip *ip,
168		 const struct ipt_entry_target *target)
169{
170	const struct ipt_ulog_info *loginfo
171	    = (const struct ipt_ulog_info *) target->data;
172
173	if (strcmp(loginfo->prefix, "") != 0)
174		printf("--ulog-prefix \"%s\" ", loginfo->prefix);
175
176	if (loginfo->nl_group != ULOG_DEFAULT_NLGROUP) {
177		printf("--ulog-nlgroup ");
178		print_groups(loginfo->nl_group);
179	}
180#ifdef KERNEL_64_USERSPACE_32
181	if (loginfo->copy_range)
182		printf("--ulog-cprange %llu ", loginfo->copy_range);
183
184	if (loginfo->qthreshold != ULOG_DEFAULT_QTHRESHOLD)
185		printf("--ulog-qthreshold %llu ", loginfo->qthreshold);
186#else
187	if (loginfo->copy_range)
188		printf("--ulog-cprange %u ", (unsigned int)loginfo->copy_range);
189
190	if (loginfo->qthreshold != ULOG_DEFAULT_QTHRESHOLD)
191		printf("--ulog-qthreshold %u ", (unsigned int)loginfo->qthreshold);
192#endif
193}
194
195/* Prints out the targinfo. */
196static void
197print(const struct ipt_ip *ip,
198      const struct ipt_entry_target *target, int numeric)
199{
200	const struct ipt_ulog_info *loginfo
201	    = (const struct ipt_ulog_info *) target->data;
202
203	printf("ULOG ");
204#ifdef KERNEL_64_USERSPACE_32
205	printf("copy_range %llu nlgroup ", loginfo->copy_range);
206#else
207	printf("copy_range %u nlgroup ", (unsigned int)loginfo->copy_range);
208#endif
209	print_groups(loginfo->nl_group);
210	if (strcmp(loginfo->prefix, "") != 0)
211		printf("prefix `%s' ", loginfo->prefix);
212#ifdef KERNEL_64_USERSPACE_32
213	printf("queue_threshold %llu ", loginfo->qthreshold);
214#else
215	printf("queue_threshold %u ", (unsigned int)loginfo->qthreshold);
216#endif
217}
218
219static struct iptables_target ulog = {
220	.next		= NULL,
221	.name		= "ULOG",
222	.version	= IPTABLES_VERSION,
223	.size		= IPT_ALIGN(sizeof(struct ipt_ulog_info)),
224	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_ulog_info)),
225	.help		= &help,
226	.init		= &init,
227	.parse		= &parse,
228	.final_check	= &final_check,
229	.print		= &print,
230	.save		= &save,
231	.extra_opts	= opts
232};
233
234void ipt_ULOG_init(void)
235{
236	register_target(&ulog);
237}
238