1 /* $OpenBSD: tcpdrop.c,v 1.4 2004/05/22 23:55:22 deraadt Exp $ */
4 * Copyright (c) 2009 Juli Mallett <jmallett@FreeBSD.org>
5 * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __FBSDID("$FreeBSD$");
23 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/socketvar.h>
27 #include <sys/sysctl.h>
29 #include <netinet/in.h>
30 #include <netinet/in_pcb.h>
32 #include <netinet/tcp_fsm.h>
33 #include <netinet/tcp_var.h>
43 #define TCPDROP_FOREIGN 0
44 #define TCPDROP_LOCAL 1
47 char hs_host
[NI_MAXHOST
];
48 char hs_service
[NI_MAXSERV
];
51 static bool tcpdrop_list_commands
= false;
53 static char *findport(const char *);
54 static struct xtcpcb
*tcpcblist(const char *, size_t *);
55 static void sockinfo(const struct sockaddr
*, struct host_service
*);
56 static bool tcpdrop(const struct sockaddr
*, const struct sockaddr
*);
57 static bool tcpdropall(void);
58 static bool tcpdropbyname(const char *, const char *, const char *,
60 static bool tcpdropconn(const struct in_conninfo
*);
61 static void usage(void);
64 * Drop a tcp connection.
67 main(int argc
, char *argv
[])
75 while ((ch
= getopt(argc
, argv
, "al")) != -1) {
81 tcpdrop_list_commands
= true;
98 if ((argc
!= 2 && argc
!= 4) || tcpdrop_list_commands
)
102 lport
= findport(argv
[0]);
103 fport
= findport(argv
[1]);
104 if (lport
== NULL
|| lport
[1] == '\0' || fport
== NULL
||
109 if (!tcpdropbyname(argv
[0], lport
, argv
[1], fport
))
111 } else if (!tcpdropbyname(argv
[0], argv
[1], argv
[2], argv
[3]))
118 findport(const char *arg
)
122 /* A strrspn() or strrpbrk() would be nice. */
123 dot
= strrchr(arg
, '.');
124 colon
= strrchr(arg
, ':');
135 static struct xtcpcb
*
136 tcpcblist(const char *name
, size_t *len0
)
143 rv
= sysctlbyname(name
, NULL
, &len
, NULL
, 0);
145 err(1, "sysctlbyname %s", name
);
148 errx(1, "%s is empty", name
);
152 errx(1, "malloc failed");
154 rv
= sysctlbyname(name
, tcp
, &len
, NULL
, 0);
156 err(1, "sysctlbyname %s", name
);
163 sockinfo(const struct sockaddr
*sa
, struct host_service
*hs
)
165 static const int flags
= NI_NUMERICHOST
| NI_NUMERICSERV
;
168 rv
= getnameinfo(sa
, sa
->sa_len
, hs
->hs_host
, sizeof hs
->hs_host
,
169 hs
->hs_service
, sizeof hs
->hs_service
, flags
);
171 err(1, "getnameinfo");
175 tcpdrop(const struct sockaddr
*lsa
, const struct sockaddr
*fsa
)
177 struct host_service local
, foreign
;
178 struct sockaddr_storage addrs
[2];
181 memcpy(&addrs
[TCPDROP_FOREIGN
], fsa
, fsa
->sa_len
);
182 memcpy(&addrs
[TCPDROP_LOCAL
], lsa
, lsa
->sa_len
);
184 sockinfo(lsa
, &local
);
185 sockinfo(fsa
, &foreign
);
187 if (tcpdrop_list_commands
) {
188 printf("tcpdrop %s %s %s %s\n", local
.hs_host
, local
.hs_service
,
189 foreign
.hs_host
, foreign
.hs_service
);
193 rv
= sysctlbyname("net.inet.tcp.drop", NULL
, NULL
, &addrs
,
196 warn("%s %s %s %s", local
.hs_host
, local
.hs_service
,
197 foreign
.hs_host
, foreign
.hs_service
);
200 printf("%s %s %s %s: dropped\n", local
.hs_host
, local
.hs_service
,
201 foreign
.hs_host
, foreign
.hs_service
);
215 tcp
= tcpcblist("net.inet.tcp.pcblist", &len
);
216 cnt
= len
/ sizeof(*tcp
);
218 for (i
= 0; i
< cnt
; ++i
) {
224 if (xpcb
->xt_len
!= sizeof(*xpcb
))
232 * Check protocol, support just v4 or v6, etc.
235 /* Skip listening sockets. */
236 if (tp
->t_state
== TCPS_LISTEN
)
239 if (!tcpdropconn(&inp
->inp_inc
))
248 tcpdropbyname(const char *lhost
, const char *lport
, const char *fhost
,
251 static const struct addrinfo hints
= {
253 * Look for streams in all domains.
255 .ai_family
= AF_UNSPEC
,
256 .ai_socktype
= SOCK_STREAM
,
258 struct addrinfo
*ail
, *local
, *aif
, *foreign
;
262 error
= getaddrinfo(lhost
, lport
, &hints
, &local
);
264 errx(1, "getaddrinfo: %s port %s: %s", lhost
, lport
,
265 gai_strerror(error
));
267 error
= getaddrinfo(fhost
, fport
, &hints
, &foreign
);
269 freeaddrinfo(local
); /* XXX gratuitous */
270 errx(1, "getaddrinfo: %s port %s: %s", fhost
, fport
,
271 gai_strerror(error
));
278 * Try every combination of local and foreign address pairs.
280 for (ail
= local
; ail
!= NULL
; ail
= ail
->ai_next
) {
281 for (aif
= foreign
; aif
!= NULL
; aif
= aif
->ai_next
) {
282 if (ail
->ai_family
!= aif
->ai_family
)
285 if (!tcpdrop(ail
->ai_addr
, aif
->ai_addr
))
291 warnx("%s %s %s %s: different address families", lhost
, lport
,
297 freeaddrinfo(foreign
);
303 tcpdropconn(const struct in_conninfo
*inc
)
305 struct sockaddr
*local
, *foreign
;
306 struct sockaddr_in6 sin6
[2];
307 struct sockaddr_in sin4
[2];
309 if (inc
->inc_isipv6
) {
310 memset(sin6
, 0, sizeof sin6
);
312 sin6
[TCPDROP_LOCAL
].sin6_len
= sizeof sin6
[TCPDROP_LOCAL
];
313 sin6
[TCPDROP_LOCAL
].sin6_family
= AF_INET6
;
314 sin6
[TCPDROP_LOCAL
].sin6_port
= inc
->inc_lport
;
315 memcpy(&sin6
[TCPDROP_LOCAL
].sin6_addr
, &inc
->inc6_laddr
,
316 sizeof inc
->inc6_laddr
);
317 local
= (struct sockaddr
*)&sin6
[TCPDROP_LOCAL
];
319 sin6
[TCPDROP_FOREIGN
].sin6_len
= sizeof sin6
[TCPDROP_FOREIGN
];
320 sin6
[TCPDROP_FOREIGN
].sin6_family
= AF_INET6
;
321 sin6
[TCPDROP_FOREIGN
].sin6_port
= inc
->inc_fport
;
322 memcpy(&sin6
[TCPDROP_FOREIGN
].sin6_addr
, &inc
->inc6_faddr
,
323 sizeof inc
->inc6_faddr
);
324 foreign
= (struct sockaddr
*)&sin6
[TCPDROP_FOREIGN
];
326 memset(&sin4
[TCPDROP_LOCAL
], 0, sizeof sin4
[TCPDROP_LOCAL
]);
328 sin4
[TCPDROP_LOCAL
].sin_len
= sizeof sin4
[TCPDROP_LOCAL
];
329 sin4
[TCPDROP_LOCAL
].sin_family
= AF_INET
;
330 sin4
[TCPDROP_LOCAL
].sin_port
= inc
->inc_lport
;
331 memcpy(&sin4
[TCPDROP_LOCAL
].sin_addr
, &inc
->inc_laddr
,
332 sizeof inc
->inc_laddr
);
333 local
= (struct sockaddr
*)&sin4
[TCPDROP_LOCAL
];
335 sin4
[TCPDROP_FOREIGN
].sin_len
= sizeof sin4
[TCPDROP_FOREIGN
];
336 sin4
[TCPDROP_FOREIGN
].sin_family
= AF_INET
;
337 sin4
[TCPDROP_FOREIGN
].sin_port
= inc
->inc_fport
;
338 memcpy(&sin4
[TCPDROP_FOREIGN
].sin_addr
, &inc
->inc_faddr
,
339 sizeof inc
->inc_faddr
);
340 foreign
= (struct sockaddr
*)&sin4
[TCPDROP_FOREIGN
];
343 return (tcpdrop(local
, foreign
));
350 "usage: tcpdrop local-address local-port foreign-address foreign-port\n"
351 " tcpdrop local-address:local-port foreign-address:foreign-port\n"
352 " tcpdrop local-address.local-port foreign-address.foreign-port\n"
353 " tcpdrop [-l] -a\n");