summary refs log tree commit diff
path: root/irc.c
diff options
context:
space:
mode:
authormultiplexd <multi@in-addr.xyz>2020-02-12 01:02:37 +0000
committerJune McEnroe <june@causal.agency>2020-02-13 00:05:52 +0000
commit1e544ce482ba97f9c4e2be114f88f11e49bdbf1b (patch)
tree5c25157df46e06fe062edb0d91809653b8587c25 /irc.c
parentAdd /list (diff)
downloadcatgirl-1e544ce482ba97f9c4e2be114f88f11e49bdbf1b.tar.gz
catgirl-1e544ce482ba97f9c4e2be114f88f11e49bdbf1b.zip
Implement source address selection
This commit adds a '-S' command line option and a "bind"
configuration file option to specify the source address to bind to when
connecting to the IRC server.
Diffstat (limited to 'irc.c')
-rw-r--r--irc.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/irc.c b/irc.c
index 05f8f9d..3ecc582 100644
--- a/irc.c
+++ b/irc.c
@@ -97,22 +97,47 @@ void ircConfig(bool insecure, FILE *cert, FILE *priv) {
 	tls_config_free(config);
 }
 
-int ircConnect(const char *host, const char *port) {
+int ircConnect(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", host, 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;