summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bounce.c7
-rw-r--r--bounce.h2
-rw-r--r--pounce.18
-rw-r--r--server.c35
4 files changed, 43 insertions, 9 deletions
diff --git a/bounce.c b/bounce.c
index eef6c12..19e2dd4 100644
--- a/bounce.c
+++ b/bounce.c
@@ -258,6 +258,7 @@ int main(int argc, char *argv[]) {
 	bool insecure = false;
 	const char *clientCert = NULL;
 	const char *clientPriv = NULL;
+	const char *serverBindHost = NULL;
 
 	const char *host = NULL;
 	const char *port = "6697";
@@ -271,7 +272,7 @@ int main(int argc, char *argv[]) {
 	const char *join = NULL;
 	const char *quit = "connection reset by purr";
 
-	const char *Opts = "!A:C:H:K:NP:U:W:a:c:ef:g:h:j:k:n:p:q:r:s:u:vw:xy:";
+	const char *Opts = "!A:C:H:K:NP:S:U:W:a:c:ef:g:h:j:k:n:p:q:r:s:u:vw:xy:";
 	const struct option LongOpts[] = {
 		{ "insecure", no_argument, NULL, '!' },
 		{ "local-ca", required_argument, NULL, 'A' },
@@ -280,6 +281,7 @@ int main(int argc, char *argv[]) {
 		{ "local-priv", required_argument, NULL, 'K' },
 		{ "no-names", no_argument, NULL, 'N' },
 		{ "local-port", required_argument, NULL, 'P' },
+		{ "bind", required_argument, NULL, 'S' },
 		{ "local-path", required_argument, NULL, 'U' },
 		{ "local-pass", required_argument, NULL, 'W' },
 		{ "sasl-plain", required_argument, NULL, 'a' },
@@ -321,6 +323,7 @@ int main(int argc, char *argv[]) {
 			break; case 'K': strlcpy(privPath, optarg, sizeof(privPath));
 			break; case 'N': stateNoNames = true;
 			break; case 'P': bindPort = optarg;
+			break; case 'S': serverBindHost = optarg;
 			break; case 'U': strlcpy(bindPath, optarg, sizeof(bindPath));
 			break; case 'W': clientPass = optarg;
 			break; case 'a': sasl = true; plain = optarg;
@@ -403,7 +406,7 @@ int main(int argc, char *argv[]) {
 		: localBind(bind, ARRAY_LEN(bind), bindHost, bindPort);
 
 	serverConfig(insecure, clientCert, clientPriv);
-	int server = serverConnect(host, port);
+	int server = serverConnect(serverBindHost, host, port);
 
 #ifdef __FreeBSD__
 	int error = cap_enter();
diff --git a/bounce.h b/bounce.h
index a0f9160..20d7d40 100644
--- a/bounce.h
+++ b/bounce.h
@@ -133,7 +133,7 @@ size_t localUnix(int fds[], size_t cap, const char *path);
 struct tls *localAccept(int *fd, int bind);
 
 void serverConfig(bool insecure, const char *cert, const char *priv);
-int serverConnect(const char *host, const char *port);
+int serverConnect(const char *bindHost, const char *host, const char *port);
 void serverRecv(void);
 void serverSend(const char *ptr, size_t len);
 void serverFormat(const char *format, ...)
diff --git a/pounce.1 b/pounce.1
index 275b5a6..c55310b 100644
--- a/pounce.1
+++ b/pounce.1
@@ -1,4 +1,4 @@
-.Dd January 17, 2020
+.Dd February 18, 2020
 .Dt POUNCE 1
 .Os
 .
@@ -14,6 +14,7 @@
 .Op Fl H Ar host
 .Op Fl K Ar priv
 .Op Fl P Ar port
+.Op Fl S Ar bind
 .Op Fl U Ar unix
 .Op Fl W Ar pass
 .Op Fl a Ar auth
@@ -121,6 +122,11 @@ Bind to
 .Ar port .
 The default port is 6697.
 .
+.It Fl S Ar host , Cm bind = Ar host
+Bind to source address
+.Ar host
+when connecting to the server.
+.
 .It Fl U Ar path , Cm local-path = Ar path
 Bind to a UNIX-domain socket at
 .Ar path .
diff --git a/server.c b/server.c
index ce5ae87..2bb897d 100644
--- a/server.c
+++ b/server.c
@@ -63,22 +63,47 @@ void serverConfig(bool insecure, const char *cert, const char *priv) {
 	tls_config_free(config);
 }
 
-int serverConnect(const char *host, const char *port) {
+int serverConnect(const char *bindHost, const char *host, const char *port) {
 	assert(client);
 
+	int error;
+	int sock = -1;
 	struct addrinfo *head;
 	struct addrinfo hints = {
 		.ai_family = AF_UNSPEC,
 		.ai_socktype = SOCK_STREAM,
 		.ai_protocol = IPPROTO_TCP,
 	};
-	int error = getaddrinfo(host, port, &hints, &head);
+
+	if (bindHost) {
+		error = getaddrinfo(bindHost, NULL, &hints, &head);
+		if (error) errx(EX_NOHOST, "%s: %s", bindHost, gai_strerror(error));
+
+		for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
+			sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+			if (sock < 0) err(EX_OSERR, "socket");
+
+			error = bind(sock, ai->ai_addr, ai->ai_addrlen);
+			if (!error) {
+				hints.ai_family = ai->ai_family;
+				break;
+			}
+
+			close(sock);
+			sock = -1;
+		}
+		if (sock < 0) err(EX_UNAVAILABLE, "%s", bindHost);
+		freeaddrinfo(head);
+	}
+
+	error = getaddrinfo(host, port, &hints, &head);
 	if (error) errx(EX_NOHOST, "%s:%s: %s", host, port, gai_strerror(error));
 
-	int sock = -1;
 	for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
-		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-		if (sock < 0) err(EX_OSERR, "socket");
+		if (sock < 0) {
+			sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+			if (sock < 0) err(EX_OSERR, "socket");
+		}
 
 		error = connect(sock, ai->ai_addr, ai->ai_addrlen);
 		if (!error) break;
an title='2019-02-21 23:17:40 -0500'>2019-02-21Replace "view" with "window"June McEnroe I think originally I didn't want to use the same word as curses WINDOW but it's really much clearer for the user if they're just called windows. UI code probably needs yet another rewrite though. Still feels messy. 2019-02-21Remove ROT13June McEnroe It's just not convenient when it can only do the whole line... 2019-02-21Clean up man pageJune McEnroe 2019-01-26Draw UI before connectingJune McEnroe Otherwise the "Traveling" message isn't visible while connecting. 2019-01-25Avoid unused variable warnings with getyxJune McEnroe 2019-01-25Add GNU/Linux build instructionsJune McEnroe