1
2/*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7#include "ipf.h"
8#include "ipt.h"
9#include <sys/ioctl.h>
10#include <sys/file.h>
11
12
13extern	char	*optarg;
14extern	struct ipread	pcap, iptext, iphex;
15extern	struct ifnet	*get_unit(char *, int);
16extern	void	init_ifp(void);
17extern	ipnat_t	*natparse(char *, int);
18extern	hostmap_t **ipf_hm_maptable;
19extern	hostmap_t *ipf_hm_maplist;
20
21ipfmutex_t	ipl_mutex, ipf_auth_mx, ipf_rw, ipf_stinsert;
22ipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
23ipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw, ipf_frcache;
24ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_authlk;
25ipfrwlock_t	ipf_tokens;
26int	opts = OPT_DONTOPEN;
27int	use_inet6 = 0;
28int	docksum = 0;
29int	pfil_delayed_copy = 0;
30int	main(int, char *[]);
31int	loadrules(char *, int);
32int	kmemcpy(char *, long, int);
33int     kstrncpy(char *, long, int n);
34int	blockreason;
35void	dumpnat(void *);
36void	dumpgroups(ipf_main_softc_t *);
37void	dumprules(frentry_t *);
38void	drain_log(char *);
39void	fixv4sums(mb_t *, ip_t *);
40
41int ipftestioctl(int, ioctlcmd_t, ...);
42int ipnattestioctl(int, ioctlcmd_t, ...);
43int ipstatetestioctl(int, ioctlcmd_t, ...);
44int ipauthtestioctl(int, ioctlcmd_t, ...);
45int ipscantestioctl(int, ioctlcmd_t, ...);
46int ipsynctestioctl(int, ioctlcmd_t, ...);
47int ipooltestioctl(int, ioctlcmd_t, ...);
48
49static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ipftestioctl,
50						      ipnattestioctl,
51						      ipstatetestioctl,
52						      ipauthtestioctl,
53						      ipsynctestioctl,
54						      ipscantestioctl,
55						      ipooltestioctl,
56						      NULL };
57static	ipf_main_softc_t	*softc = NULL;
58
59
60int
61main(int argc, char *argv[])
62{
63	char	*datain, *iface, *ifname, *logout;
64	int	fd, i, dir, c, loaded, dump, hlen;
65	struct	in_addr	sip;
66	struct	ifnet	*ifp;
67	struct	ipread	*r;
68	mb_t	mb, *m, *n;
69	ip_t	*ip;
70
71	m = &mb;
72	dir = 0;
73	dump = 0;
74	hlen = 0;
75	loaded = 0;
76	r = &iptext;
77	iface = NULL;
78	logout = NULL;
79	datain = NULL;
80	sip.s_addr = 0;
81	ifname = "anon0";
82
83	initparse();
84
85	ipf_load_all();
86
87	softc = ipf_create_all(NULL);
88	if (softc == NULL)
89		exit(1);
90
91	if (ipf_init_all(softc) == -1)
92		exit(1);
93
94	i = 1;
95	if (ipftestioctl(IPL_LOGIPF, SIOCFRENB, &i) != 0)
96		exit(1);
97
98	while ((c = getopt(argc, argv, "6bCdDF:i:I:l:N:P:or:RS:T:vxX")) != -1)
99		switch (c)
100		{
101		case '6' :
102#ifdef	USE_INET6
103			use_inet6 = 1;
104#else
105			fprintf(stderr, "IPv6 not supported\n");
106			exit(1);
107#endif
108			break;
109		case 'b' :
110			opts |= OPT_BRIEF;
111			break;
112		case 'd' :
113			opts |= OPT_DEBUG;
114			break;
115		case 'C' :
116			docksum = 1;
117			break;
118		case 'D' :
119			dump = 1;
120			break;
121		case 'F' :
122			if (strcasecmp(optarg, "pcap") == 0)
123				r = &pcap;
124			else if (strcasecmp(optarg, "hex") == 0)
125				r = &iphex;
126			else if (strcasecmp(optarg, "text") == 0)
127				r = &iptext;
128			break;
129		case 'i' :
130			datain = optarg;
131			break;
132		case 'I' :
133			ifname = optarg;
134			break;
135		case 'l' :
136			logout = optarg;
137			break;
138		case 'N' :
139			if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl,
140					    optarg) == -1)
141				return (-1);
142			loaded = 1;
143			opts |= OPT_NAT;
144			break;
145		case 'o' :
146			opts |= OPT_SAVEOUT;
147			break;
148		case 'P' :
149			if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1)
150				return (-1);
151			loaded = 1;
152			break;
153		case 'r' :
154			if (ipf_parsefile(-1, ipf_addrule, iocfunctions,
155					  optarg) == -1)
156				return (-1);
157			loaded = 1;
158			break;
159		case 'S' :
160			sip.s_addr = inet_addr(optarg);
161			break;
162		case 'R' :
163			opts |= OPT_NORESOLVE;
164			break;
165		case 'T' :
166			ipf_dotuning(-1, optarg, ipftestioctl);
167			break;
168		case 'v' :
169			opts |= OPT_VERBOSE;
170			break;
171		case 'x' :
172			opts |= OPT_HEX;
173			break;
174		}
175
176	if (loaded == 0) {
177		(void)fprintf(stderr,"no rules loaded\n");
178		exit(-1);
179	}
180
181	if (opts & OPT_SAVEOUT)
182		init_ifp();
183
184	if (datain)
185		fd = (*r->r_open)(datain);
186	else
187		fd = (*r->r_open)("-");
188
189	if (fd < 0) {
190		perror("error opening input");
191		exit(-1);
192	}
193
194	m->m_data = (char *)m->mb_buf;
195	while ((i = (*r->r_readip)(m, &iface, &dir)) > 0) {
196
197		if ((iface == NULL) || (*iface == '\0'))
198			iface = ifname;
199
200		ip = MTOD(m, ip_t *);
201		ifp = get_unit(iface, IP_V(ip));
202
203		if (IP_V(ip) == 4) {
204			if ((r->r_flags & R_DO_CKSUM) || docksum)
205				fixv4sums(m, ip);
206			hlen = IP_HL(ip) << 2;
207			if (sip.s_addr)
208				dir = !(sip.s_addr == ip->ip_src.s_addr);
209		}
210#ifdef	USE_INET6
211		else
212			hlen = sizeof(ip6_t);
213#endif
214		/* ipfr_slowtimer(); */
215		blockreason = 0;
216		m = &mb;
217		m->mb_ifp = ifp;
218		m->mb_len = i;
219		i = ipf_check(softc, ip, hlen, ifp, dir, &m);
220		if ((opts & OPT_NAT) == 0)
221			switch (i)
222			{
223			case -4 :
224				(void)printf("preauth");
225				break;
226			case -3 :
227				(void)printf("account");
228				break;
229			case -2 :
230				(void)printf("auth");
231				break;
232			case -1 :
233				(void)printf("block");
234				break;
235			case 0 :
236				(void)printf("pass");
237				break;
238			case 1 :
239				if (m == NULL)
240					(void)printf("bad-packet");
241				else
242					(void)printf("nomatch");
243				break;
244			case 3 :
245				(void)printf("block return-rst");
246				break;
247			case 4 :
248				(void)printf("block return-icmp");
249				break;
250			case 5 :
251				(void)printf("block return-icmp-as-dest");
252				break;
253			default :
254				(void)printf("recognised( return %#x\n", i));
255				break;
256			}
257
258		if (!(opts & OPT_BRIEF)) {
259			putchar(' ');
260			if (m != NULL)
261				printpacket(dir, m);
262			else
263				printpacket(dir, &mb);
264			printf("--------------");
265		} else if ((opts & (OPT_BRIEF|OPT_NAT)) ==
266			   (OPT_NAT|OPT_BRIEF)) {
267			if (m != NULL)
268				printpacket(dir, m);
269			else
270				PRINTF("%d\n", blockreason);
271		}
272
273		ipf_state_flush(softc, 1, 0);
274
275		if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL))
276			(*ifp->if_output)(ifp, (void *)m, NULL, 0);
277
278		while ((m != NULL) && (m != &mb)) {
279			n = m->mb_next;
280			freembt(m);
281			m = n;
282		}
283
284		if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF))
285			putchar('\n');
286		dir = 0;
287		if (iface != ifname) {
288			free(iface);
289			iface = ifname;
290		}
291		m = &mb;
292		m->mb_data = (char *)m->mb_buf;
293	}
294
295	if (i != 0)
296		fprintf(stderr, "readip failed: %d\n", i);
297	(*r->r_close)();
298
299	if (logout != NULL) {
300		drain_log(logout);
301	}
302
303	if (dump == 1)  {
304		dumpnat(softc->ipf_nat_soft);
305		ipf_state_dump(softc, softc->ipf_state_soft);
306		ipf_lookup_dump(softc, softc->ipf_state_soft);
307		dumpgroups(softc);
308	}
309
310	ipf_fini_all(softc);
311
312	ipf_destroy_all(softc);
313
314	ipf_unload_all();
315
316	ipf_mutex_clean();
317	ipf_rwlock_clean();
318
319	if (getenv("FINDLEAKS")) {
320		fflush(stdout);
321		abort();
322	}
323	return (0);
324}
325
326
327int ipftestioctl(int dev, ioctlcmd_t cmd, ...)
328{
329	caddr_t data;
330	va_list ap;
331	int i;
332
333	dev = dev;	/* gcc -Wextra */
334	va_start(ap, cmd);
335	data = va_arg(ap, caddr_t);
336	va_end(ap);
337
338	i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD);
339	if (opts & OPT_DEBUG)
340		fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n",
341			(u_int)cmd, data, i, softc->ipf_interror);
342	if (i != 0) {
343		errno = i;
344		return (-1);
345	}
346	return (0);
347}
348
349
350int
351ipnattestioctl(int dev, ioctlcmd_t cmd, ...)
352{
353	caddr_t data;
354	va_list ap;
355	int i;
356
357	dev = dev;	/* gcc -Wextra */
358	va_start(ap, cmd);
359	data = va_arg(ap, caddr_t);
360	va_end(ap);
361
362	i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD);
363	if (opts & OPT_DEBUG)
364		fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n",
365			(u_int)cmd, data, i);
366	if (i != 0) {
367		errno = i;
368		return (-1);
369	}
370	return (0);
371}
372
373
374int
375ipstatetestioctl(int dev, ioctlcmd_t cmd, ...)
376{
377	caddr_t data;
378	va_list ap;
379	int i;
380
381	dev = dev;	/* gcc -Wextra */
382	va_start(ap, cmd);
383	data = va_arg(ap, caddr_t);
384	va_end(ap);
385
386	i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD);
387	if ((opts & OPT_DEBUG) || (i != 0))
388		fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n",
389			(u_int)cmd, data, i);
390	if (i != 0) {
391		errno = i;
392		return (-1);
393	}
394	return (0);
395}
396
397
398int
399ipauthtestioctl(int dev, ioctlcmd_t cmd, ...)
400{
401	caddr_t data;
402	va_list ap;
403	int i;
404
405	dev = dev;	/* gcc -Wextra */
406	va_start(ap, cmd);
407	data = va_arg(ap, caddr_t);
408	va_end(ap);
409
410	i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD);
411	if ((opts & OPT_DEBUG) || (i != 0))
412		fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n",
413			(u_int)cmd, data, i);
414	if (i != 0) {
415		errno = i;
416		return (-1);
417	}
418	return (0);
419}
420
421
422int
423ipscantestioctl(int dev, ioctlcmd_t cmd, ...)
424{
425	caddr_t data;
426	va_list ap;
427	int i;
428
429	dev = dev;	/* gcc -Wextra */
430	va_start(ap, cmd);
431	data = va_arg(ap, caddr_t);
432	va_end(ap);
433
434	i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD);
435	if ((opts & OPT_DEBUG) || (i != 0))
436		fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n",
437			(u_int)cmd, data, i);
438	if (i != 0) {
439		errno = i;
440		return (-1);
441	}
442	return (0);
443}
444
445
446int
447ipsynctestioctl(int dev, ioctlcmd_t cmd, ...)
448{
449	caddr_t data;
450	va_list ap;
451	int i;
452
453	dev = dev;	/* gcc -Wextra */
454	va_start(ap, cmd);
455	data = va_arg(ap, caddr_t);
456	va_end(ap);
457
458	i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD);
459	if ((opts & OPT_DEBUG) || (i != 0))
460		fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n",
461			(u_int)cmd, data, i);
462	if (i != 0) {
463		errno = i;
464		return (-1);
465	}
466	return (0);
467}
468
469
470int
471ipooltestioctl(int dev, ioctlcmd_t cmd, ...)
472{
473	caddr_t data;
474	va_list ap;
475	int i;
476
477	dev = dev;	/* gcc -Wextra */
478	va_start(ap, cmd);
479	data = va_arg(ap, caddr_t);
480	va_end(ap);
481
482	i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD);
483	if ((opts & OPT_DEBUG) || (i != 0))
484		fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n",
485			(u_int)cmd, data, i, softc->ipf_interror);
486	if (i != 0) {
487		errno = i;
488		return (-1);
489	}
490	return (0);
491}
492
493
494int
495kmemcpy(char *addr, long offset, int size)
496{
497	bcopy((char *)offset, addr, size);
498	return (0);
499}
500
501
502int
503kstrncpy(char *buf, long pos, int n)
504{
505	char *ptr;
506
507	ptr = (char *)pos;
508
509	while ((n > 0) && (*buf++ = *ptr++))
510		;
511	return (0);
512}
513
514
515/*
516 * Display the built up NAT table rules and mapping entries.
517 */
518void
519dumpnat(void *arg)
520{
521	ipf_nat_softc_t *softn = arg;
522	hostmap_t *hm;
523	ipnat_t	*ipn;
524	nat_t *nat;
525
526	printf("List of active MAP/Redirect filters:\n");
527	for (ipn = softn->ipf_nat_list; ipn != NULL; ipn = ipn->in_next)
528		printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
529	printf("\nList of active sessions:\n");
530	for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
531		printactivenat(nat, opts, 0);
532		if (nat->nat_aps)
533			printf("\tproxy active\n");
534	}
535
536	printf("\nHostmap table:\n");
537	for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next)
538		printhostmap(hm, hm->hm_hv);
539}
540
541
542void
543dumpgroups(ipf_main_softc_t *softc)
544{
545	frgroup_t *fg;
546	int i;
547
548	printf("List of groups configured (set 0)\n");
549	for (i = 0; i < IPL_LOGSIZE; i++)
550		for (fg =  softc->ipf_groups[i][0]; fg != NULL;
551		     fg = fg->fg_next) {
552			printf("Dev.%d. Group %s Ref %d Flags %#x\n",
553				i, fg->fg_name, fg->fg_ref, fg->fg_flags);
554			dumprules(fg->fg_start);
555		}
556
557	printf("List of groups configured (set 1)\n");
558	for (i = 0; i < IPL_LOGSIZE; i++)
559		for (fg =  softc->ipf_groups[i][1]; fg != NULL;
560		     fg = fg->fg_next) {
561			printf("Dev.%d. Group %s Ref %d Flags %#x\n",
562				i, fg->fg_name, fg->fg_ref, fg->fg_flags);
563			dumprules(fg->fg_start);
564		}
565
566	printf("Rules configured (set 0, in)\n");
567	dumprules(softc->ipf_rules[0][0]);
568	printf("Rules configured (set 0, out)\n");
569	dumprules(softc->ipf_rules[1][0]);
570	printf("Rules configured (set 1, in)\n");
571	dumprules(softc->ipf_rules[0][1]);
572	printf("Rules configured (set 1, out)\n");
573	dumprules(softc->ipf_rules[1][1]);
574
575	printf("Accounting rules configured (set 0, in)\n");
576	dumprules(softc->ipf_acct[0][0]);
577	printf("Accounting rules configured (set 0, out)\n");
578	dumprules(softc->ipf_acct[0][1]);
579	printf("Accounting rules configured (set 1, in)\n");
580	dumprules(softc->ipf_acct[1][0]);
581	printf("Accounting rules configured (set 1, out)\n");
582	dumprules(softc->ipf_acct[1][1]);
583}
584
585void
586dumprules(frentry_t *rulehead)
587{
588	frentry_t *fr;
589
590	for (fr = rulehead; fr != NULL; fr = fr->fr_next) {
591#ifdef	USE_QUAD_T
592		printf("%"PRIu64" ",(unsigned long long)fr->fr_hits);
593#else
594		printf("%ld ", fr->fr_hits);
595#endif
596		printfr(fr, ipftestioctl);
597	}
598}
599
600
601void
602drain_log(char *filename)
603{
604	char buffer[DEFAULT_IPFLOGSIZE];
605	struct iovec iov;
606	struct uio uio;
607	size_t resid;
608	int fd, i;
609
610	fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
611	if (fd == -1) {
612		perror("drain_log:open");
613		return;
614	}
615
616	for (i = 0; i <= IPL_LOGMAX; i++)
617		while (1) {
618			bzero((char *)&iov, sizeof(iov));
619			iov.iov_base = buffer;
620			iov.iov_len = sizeof(buffer);
621
622			bzero((char *)&uio, sizeof(uio));
623			uio.uio_iov = &iov;
624			uio.uio_iovcnt = 1;
625			uio.uio_resid = iov.iov_len;
626			resid = uio.uio_resid;
627
628			if (ipf_log_read(softc, i, &uio) == 0) {
629				/*
630				 * If nothing was read then break out.
631				 */
632				if (uio.uio_resid == resid)
633					break;
634				write(fd, buffer, resid - uio.uio_resid);
635			} else
636				break;
637	}
638
639	close(fd);
640}
641
642
643void
644fixv4sums(mb_t *m, ip_t *ip)
645{
646	u_char *csump, *hdr, p;
647	fr_info_t tmp;
648	int len;
649
650	p = 0;
651	len = 0;
652	bzero((char *)&tmp, sizeof(tmp));
653
654	csump = (u_char *)ip;
655	if (IP_V(ip) == 4) {
656		ip->ip_sum = 0;
657		ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2);
658		tmp.fin_hlen = IP_HL(ip) << 2;
659		csump += IP_HL(ip) << 2;
660		p = ip->ip_p;
661		len = ntohs(ip->ip_len);
662#ifdef USE_INET6
663	} else if (IP_V(ip) == 6) {
664		tmp.fin_hlen = sizeof(ip6_t);
665		csump += sizeof(ip6_t);
666		p = ((ip6_t *)ip)->ip6_nxt;
667		len = ntohs(((ip6_t *)ip)->ip6_plen);
668		len += sizeof(ip6_t);
669#endif
670	}
671	tmp.fin_plen = len;
672	tmp.fin_dlen = len - tmp.fin_hlen;
673
674	switch (p)
675	{
676	case IPPROTO_TCP :
677		hdr = csump;
678		csump += offsetof(tcphdr_t, th_sum);
679		break;
680	case IPPROTO_UDP :
681		hdr = csump;
682		csump += offsetof(udphdr_t, uh_sum);
683		break;
684	case IPPROTO_ICMP :
685		hdr = csump;
686		csump += offsetof(icmphdr_t, icmp_cksum);
687		break;
688	default :
689		csump = NULL;
690		hdr = NULL;
691		break;
692	}
693	if (hdr != NULL) {
694		tmp.fin_m = m;
695		tmp.fin_mp = &m;
696		tmp.fin_dp = hdr;
697		tmp.fin_ip = ip;
698		tmp.fin_plen = len;
699		*csump = 0;
700		*(u_short *)csump = fr_cksum(&tmp, ip, p, hdr);
701	}
702}
703
704void
705ip_fillid(struct ip *ip)
706{
707	static uint16_t ip_id;
708
709	ip->ip_id = ip_id++;
710}
711