1/* $OpenBSD: tcpdrop.c,v 1.21 2023/02/06 18:14:10 millert Exp $ */
2
3/*
4 * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/socket.h>
20#include <sys/sysctl.h>
21#include <sys/queue.h>
22#include <sys/timeout.h>
23
24#include <netinet/in.h>
25#include <netinet/tcp.h>
26#include <netinet/tcp_timer.h>
27#include <netinet/tcp_var.h>
28
29#include <err.h>
30#include <netdb.h>
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <resolv.h>
36
37__dead void	 usage(void);
38
39__dead void
40usage(void)
41{
42	extern char	*__progname;
43
44	fprintf(stderr,
45	    "usage: %s local-addr local-port remote-addr remote-port\n",
46	    __progname);
47	exit(1);
48}
49
50/*
51 * Drop a tcp connection.
52 */
53int
54main(int argc, char **argv)
55{
56	int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_DROP };
57	struct addrinfo hints, *ail, *aif, *laddr, *faddr;
58	char fhbuf[NI_MAXHOST], fsbuf[NI_MAXSERV];
59	char lhbuf[NI_MAXHOST], lsbuf[NI_MAXSERV];
60	char *laddr1, *addr1, *port1, *faddr2, *addr2, *port2;
61	struct tcp_ident_mapping tir;
62	int gaierr, rval = 0;
63
64	if (unveil(_PATH_HOSTS, "r") == -1)
65		err(1, "unveil %s", _PATH_HOSTS);
66	if (unveil(_PATH_RESCONF, "r") == -1)
67		err(1, "unveil %s", _PATH_RESCONF);
68	if (unveil(NULL, NULL) == -1)
69		err(1, "unveil");
70
71	memset(&hints, 0, sizeof(hints));
72	hints.ai_family = AF_UNSPEC;
73	hints.ai_socktype = SOCK_STREAM;
74
75	if (argc == 3) {
76		char *dot;
77
78		laddr1 = addr1 = strdup(argv[1]);
79		if (!addr1)
80			err(1, "strdup");
81		port1 = strrchr(addr1, ':');
82		dot = strrchr(addr1, '.');
83		if (dot > port1)
84			port1 = dot;
85		if (port1)
86			*port1++ = '\0';
87		else
88			usage();
89
90		faddr2 = addr2 = strdup(argv[2]);
91		if (!addr2)
92			err(1, "strdup");
93		port2 = strrchr(addr2, ':');
94		dot = strrchr(addr2, '.');
95		if (dot > port2)
96			port2 = dot;
97		if (port2)
98			*port2++ = '\0';
99		else
100			usage();
101	} else if (argc == 5) {
102		laddr1 = addr1 = argv[1];
103		port1 = argv[2];
104		faddr2 = addr2 = argv[3];
105		port2 = argv[4];
106	} else
107		usage();
108
109	if (addr1[0] == '[' && addr1[strlen(addr1) - 1] == ']') {
110		laddr1 = strdup(addr1);
111		if (!laddr1)
112			err(1, "strdup");
113		laddr1[strlen(laddr1) - 1] = '\0';
114		laddr1++;
115	}
116	if (addr2[0] == '[' && addr2[strlen(addr2) - 1] == ']') {
117		faddr2 = strdup(addr2);
118		if (!faddr2)
119			err(1, "strdup");
120		faddr2[strlen(faddr2) - 1] = '\0';
121		faddr2++;
122	}
123
124	if ((gaierr = getaddrinfo(laddr1, port1, &hints, &laddr)) != 0)
125		errx(1, "%s port %s: %s", addr1, port1,
126		    gai_strerror(gaierr));
127
128	if ((gaierr = getaddrinfo(faddr2, port2, &hints, &faddr)) != 0)
129		errx(1, "%s port %s: %s", addr2, port2,
130		    gai_strerror(gaierr));
131
132	rval = 1;
133	for (ail = laddr; ail; ail = ail->ai_next) {
134		for (aif = faddr; aif; aif = aif->ai_next) {
135			if (ail->ai_family != aif->ai_family)
136				continue;
137			rval = 0;
138			memset(&tir, 0, sizeof(tir));
139			memcpy(&tir.faddr, aif->ai_addr, aif->ai_addrlen);
140			memcpy(&tir.laddr, ail->ai_addr, ail->ai_addrlen);
141
142			if ((gaierr = getnameinfo(aif->ai_addr, aif->ai_addrlen,
143			    fhbuf, sizeof(fhbuf), fsbuf, sizeof(fsbuf),
144			    NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
145				errx(1, "getnameinfo: %s", gai_strerror(gaierr));
146			if ((gaierr = getnameinfo(ail->ai_addr, ail->ai_addrlen,
147			    lhbuf, sizeof(lhbuf), lsbuf, sizeof(lsbuf),
148			    NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
149				errx(1, "getnameinfo: %s", gai_strerror(gaierr));
150
151			if (sysctl(mib, sizeof (mib) / sizeof (int), NULL,
152			    NULL, &tir, sizeof(tir)) == -1) {
153				rval = 1;
154				warn("%s %s %s %s", lhbuf, lsbuf, fhbuf, fsbuf);
155			} else {
156				if (aif->ai_family == PF_INET6)
157					printf("[%s]:%s [%s]:%s dropped\n",
158					    lhbuf, lsbuf, fhbuf, fsbuf);
159				else
160					printf("%s:%s %s:%s dropped\n",
161					    lhbuf, lsbuf, fhbuf, fsbuf);
162			}
163		}
164	}
165	freeaddrinfo(laddr);
166	freeaddrinfo(faddr);
167	exit(rval);
168}
169