summaryrefslogtreecommitdiffstats
path: root/libexec/tftp-proxy/tftp-proxy.c
diff options
context:
space:
mode:
authordlg <dlg@openbsd.org>2011-09-28 12:38:59 +0000
committerdlg <dlg@openbsd.org>2011-09-28 12:38:59 +0000
commite8048d39b574e272f24d761163b8c01ccbba8947 (patch)
treefc61851f449d4eda1ce605f148808b9999e9cea2 /libexec/tftp-proxy/tftp-proxy.c
parentdisable the fifo on m series systems by telling the driver its a 16550 (diff)
downloadwireguard-openbsd-e8048d39b574e272f24d761163b8c01ccbba8947.tar.xz
wireguard-openbsd-e8048d39b574e272f24d761163b8c01ccbba8947.zip
tweak tftp-proxy to:
1. use a BINDANY socket to connect from the proxy to the server using the clients address. 2. fork a child to do the work so inetd doesnt keep trying to send more packets to the proxy, as per doco in the inetd manpage for dgram wait sockets. because of 1 you now have to add a pass out divert-reply for the proxy to server packet to your pf ruleset. this allows a series of rapid tftp connections from the same host to a server in my environment. without this diff there's several minutes of waiting in between requests because of issues with the rules from previous requests stealing packets but not forwarding them combined with inetd giving too many packets to tftp-proxy that only expects to handle one. this is going in so i can hack on PFRULE_ONCE support. ok mikeb@ sthen@
Diffstat (limited to 'libexec/tftp-proxy/tftp-proxy.c')
-rw-r--r--libexec/tftp-proxy/tftp-proxy.c119
1 files changed, 57 insertions, 62 deletions
diff --git a/libexec/tftp-proxy/tftp-proxy.c b/libexec/tftp-proxy/tftp-proxy.c
index bf592e7d1db..ad9c48ca65e 100644
--- a/libexec/tftp-proxy/tftp-proxy.c
+++ b/libexec/tftp-proxy/tftp-proxy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tftp-proxy.c,v 1.7 2011/05/05 12:25:51 sthen Exp $
+/* $OpenBSD: tftp-proxy.c,v 1.8 2011/09/28 12:38:59 dlg Exp $
*
* Copyright (c) 2005 DLS Internet Services
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
@@ -84,12 +84,11 @@ main(int argc, char *argv[])
struct msghdr msg;
struct iovec iov;
- struct sockaddr_storage from, server, proxy_to_server;
- socklen_t j;
+ struct sockaddr_storage from, server;
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
- while ((c = getopt(argc, argv, "vw:")) != -1)
+ while ((c = getopt(argc, argv, "vw:")) != -1) {
switch (c) {
case 'v':
verbose++;
@@ -105,26 +104,6 @@ main(int argc, char *argv[])
usage();
break;
}
-
- /* open /dev/pf */
- init_filter(NULL, verbose);
-
- tzset();
-
- pw = getpwnam(NOPRIV_USER);
- if (!pw) {
- syslog(LOG_ERR, "no such user %s: %m", NOPRIV_USER);
- exit(1);
- }
- if (chroot(CHROOT_DIR) || chdir("/")) {
- syslog(LOG_ERR, "chroot %s: %m", CHROOT_DIR);
- exit(1);
- }
- if (setgroups(1, &pw->pw_gid) ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
- syslog(LOG_ERR, "can't revoke privs: %m");
- exit(1);
}
/* non-blocking io */
@@ -158,13 +137,56 @@ main(int argc, char *argv[])
exit(1);
}
- close(fd);
- close(1);
-
memset(&server, 0, sizeof(server));
server.ss_family = from.ss_family;
server.ss_len = from.ss_len;
+ close(fd);
+ close(1);
+
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "couldn't fork");
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+
+ /* establish a new outbound connection to the remote server */
+ if ((out_fd = socket(((struct sockaddr *)&from)->sa_family,
+ SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ syslog(LOG_ERR, "couldn't create new socket");
+ exit(1);
+ }
+
+ if (setsockopt(out_fd, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)) == -1) {
+ syslog(LOG_ERR, "couldn't enable BINDANY");
+ exit(1);
+ }
+
+ /* open /dev/pf */
+ init_filter(NULL, verbose);
+
+ tzset();
+
+ /* revoke privs */
+ pw = getpwnam(NOPRIV_USER);
+ if (!pw) {
+ syslog(LOG_ERR, "no such user %s: %m", NOPRIV_USER);
+ exit(1);
+ }
+ if (chroot(CHROOT_DIR) || chdir("/")) {
+ syslog(LOG_ERR, "chroot %s: %m", CHROOT_DIR);
+ exit(1);
+ }
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
+ syslog(LOG_ERR, "can't revoke privs: %m");
+ exit(1);
+ }
+
/* get server address and port */
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@@ -191,10 +213,9 @@ main(int argc, char *argv[])
exit(0);
}
- /* establish a new outbound connection to the remote server */
- if ((out_fd = socket(((struct sockaddr *)&from)->sa_family,
- SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- syslog(LOG_ERR, "couldn't create new socket");
+ /* bind ourselves to the clients IP for the connection to the server */
+ if (bind(out_fd, (struct sockaddr *)&from, from.ss_len) == -1) {
+ syslog(LOG_ERR, "couldn't bind to client address: %m");
exit(1);
}
@@ -204,23 +225,15 @@ main(int argc, char *argv[])
exit(1);
}
- j = sizeof(struct sockaddr_storage);
- if ((getsockname(out_fd, (struct sockaddr *)&proxy_to_server,
- &j)) < 0) {
- syslog(LOG_ERR, "getsockname: %m");
- exit(1);
- }
-
- if (verbose)
- syslog(LOG_INFO, "%s:%d -> %s:%d -> %s:%d \"%s %s\"",
+ if (verbose) {
+ syslog(LOG_INFO, "%s:%d -> %s:%d \"%s %s\"",
sock_ntop((struct sockaddr *)&from),
ntohs(((struct sockaddr_in *)&from)->sin_port),
- sock_ntop((struct sockaddr *)&proxy_to_server),
- ntohs(((struct sockaddr_in *)&proxy_to_server)->sin_port),
sock_ntop((struct sockaddr *)&server),
ntohs(((struct sockaddr_in *)&server)->sin_port),
opcode(ntohs(tp->th_opcode)),
tp->th_stuff);
+ }
/* get ready to add rdr and pass rules */
if (prepare_commit(1) == -1) {
@@ -228,17 +241,6 @@ main(int argc, char *argv[])
exit(1);
}
- /* rdr from server to us on our random port -> client on its port */
- if (add_rdr(1, (struct sockaddr *)&server,
- (struct sockaddr *)&proxy_to_server,
- ntohs(((struct sockaddr_in *)&proxy_to_server)->sin_port),
- (struct sockaddr *)&from,
- ntohs(((struct sockaddr_in *)&from)->sin_port),
- IPPROTO_UDP) == -1) {
- syslog(LOG_ERR, "couldn't add rdr");
- exit(1);
- }
-
/* explicitly allow the packets to return back to the client (which pf
* will see post-rdr) */
if (add_filter(1, PF_IN, (struct sockaddr *)&server,
@@ -256,15 +258,6 @@ main(int argc, char *argv[])
exit(1);
}
- /* and just in case, to pass out from us to the server */
- if (add_filter(1, PF_OUT, (struct sockaddr *)&proxy_to_server,
- (struct sockaddr *)&server,
- ntohs(((struct sockaddr_in *)&server)->sin_port),
- IPPROTO_UDP) == -1) {
- syslog(LOG_ERR, "couldn't add pass out");
- exit(1);
- }
-
if (do_commit() == -1) {
syslog(LOG_ERR, "couldn't commit pf rules");
exit(1);
@@ -276,6 +269,8 @@ main(int argc, char *argv[])
exit(1);
}
+ close(out_fd);
+
/* allow the transfer to start to establish a state */
sleep(transwait);