summaryrefslogtreecommitdiffstats
path: root/libexec/tftp-proxy
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
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')
-rw-r--r--libexec/tftp-proxy/tftp-proxy.839
-rw-r--r--libexec/tftp-proxy/tftp-proxy.c119
2 files changed, 73 insertions, 85 deletions
diff --git a/libexec/tftp-proxy/tftp-proxy.8 b/libexec/tftp-proxy/tftp-proxy.8
index c091fce4363..a367abc13f1 100644
--- a/libexec/tftp-proxy/tftp-proxy.8
+++ b/libexec/tftp-proxy/tftp-proxy.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tftp-proxy.8,v 1.5 2011/06/22 08:39:15 sthen Exp $
+.\" $OpenBSD: tftp-proxy.8,v 1.6 2011/09/28 12:38:59 dlg Exp $
.\"
.\" Copyright (c) 2005 joshua stein <jcs@openbsd.org>
.\"
@@ -25,7 +25,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: June 22 2011 $
+.Dd $Mdocdate: September 28 2011 $
.Dt TFTP-PROXY 8
.Os
.Sh NAME
@@ -47,34 +47,25 @@ rule using the
.Ar divert-to
option, after which the proxy connects to the server on behalf of
the client.
+The connection from the proxy to the server needs to be passed by
+a rule with divert-reply set.
.Pp
-The proxy establishes a
+The proxy inserts a
.Xr pf 4
-.Ar rdr-to
-pass rule using the
+pass rules using the
.Ar anchor
-facility to rewrite packets between the client and the server.
-Once the rule is established,
+facility to allow payload packets between the client and the server.
+Once the rules are inserted,
.Nm
forwards the initial request from the client to the server to begin the
transfer.
After
.Ar transwait
-seconds, the NAT state is assumed to have been established and the
+seconds, the states are assumed to have been established and the
.Xr pf 4
-rule is deleted and the program exits.
-Once the transfer between the client and the server is completed, the
-NAT state will naturally expire.
-.Pp
-Assuming the TFTP command request is from $client to $server, the
-proxy connected to the server using the $proxy source address, and
-$port is negotiated,
-.Nm
-adds the following rule to the anchor:
-.Bd -literal -offset indent
-pass in quick proto udp from $server to $proxy \e
- port $port rdr-to $client
-.Ed
+rules are deleted and the program exits.
+Once the transfer between the client and the server is completed the
+states will naturally expire.
.Pp
The options are as follows:
.Bl -tag -width Ds
@@ -96,8 +87,10 @@ The anchor is mandatory.
Adjust the rule as needed for your configuration.
.Bd -literal -offset indent
anchor "tftp-proxy/*"
-pass in quick on $int_if inet proto udp from $lan to any port tftp \e
+pass in quick on $int_if inet proto udp from $lan to port tftp \e
divert-to 127.0.0.1 port 6969
+pass out quick on $ext_if inet proto udp from $lan to port tftp \e
+ group proxy divert-reply
.Ed
.Pp
.Xr inetd 8
@@ -108,7 +101,7 @@ An example
.Xr inetd.conf 5
entry follows:
.Bd -literal -offset indent
-127.0.0.1:6969 dgram udp wait root \e
+127.0.0.1:6969 dgram udp wait root:proxy \e
/usr/libexec/tftp-proxy tftp-proxy
.Ed
.Sh SEE ALSO
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);