summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--catgirl.16
-rw-r--r--chat.c7
-rw-r--r--chat.h2
-rw-r--r--irc.c35
4 files changed, 42 insertions, 8 deletions
diff --git a/catgirl.1 b/catgirl.1
index dc5aefb..672abfc 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -12,6 +12,7 @@
.Op Fl C Ar copy
.Op Fl H Ar hash
.Op Fl O Ar open
+.Op Fl S Ar bind
.Op Fl a Ar auth
.Op Fl c Ar cert
.Op Fl h Ar host
@@ -85,6 +86,11 @@ Disable the
.Ic /quote
commands.
.
+.It Fl S Ar host , Cm bind = Ar host
+Bind to source address
+.Ar host
+when connecting to the server.
+.
.It Fl a Ar user Ns : Ns Ar pass , Cm sasl-plain = Ar user Ns : Ns Ar pass
Authenticate as
.Ar user
diff --git a/chat.c b/chat.c
index 2c41d43..c0950fb 100644
--- a/chat.c
+++ b/chat.c
@@ -82,6 +82,7 @@ int main(int argc, char *argv[]) {
setlocale(LC_CTYPE, "");
bool insecure = false;
+ const char *bind = NULL;
const char *host = NULL;
const char *port = "6697";
const char *cert = NULL;
@@ -93,13 +94,14 @@ int main(int argc, char *argv[]) {
const char *user = NULL;
const char *real = NULL;
- const char *Opts = "!C:H:O:Ra:c:eh:j:k:n:p:r:s:u:vw:";
+ const char *Opts = "!C:H:O:RS:a:c:eh:j:k:n:p:r:s:u:vw:";
const struct option LongOpts[] = {
{ "insecure", no_argument, NULL, '!' },
{ "copy", required_argument, NULL, 'C' },
{ "hash", required_argument, NULL, 'H' },
{ "open", required_argument, NULL, 'O' },
{ "restrict", no_argument, NULL, 'R' },
+ { "bind", required_argument, NULL, 'S' },
{ "sasl-plain", required_argument, NULL, 'a' },
{ "cert", required_argument, NULL, 'c' },
{ "sasl-external", no_argument, NULL, 'e' },
@@ -124,6 +126,7 @@ int main(int argc, char *argv[]) {
break; case 'H': hashInit = strtoul(optarg, NULL, 0);
break; case 'O': utilPush(&urlOpenUtil, optarg);
break; case 'R': self.restricted = true;
+ break; case 'S': bind = optarg;
break; case 'a': sasl = true; self.plain = optarg;
break; case 'c': cert = optarg;
break; case 'e': sasl = true;
@@ -182,7 +185,7 @@ int main(int argc, char *argv[]) {
uiFormat(Network, Cold, NULL, "Traveling...");
uiDraw();
- int irc = ircConnect(host, port);
+ int irc = ircConnect(bind, host, port);
if (pass) ircFormat("PASS :%s\r\n", pass);
if (sasl) ircFormat("CAP REQ :sasl\r\n");
ircFormat("CAP LS\r\n");
diff --git a/chat.h b/chat.h
index 6af5ef7..ed6dc2f 100644
--- a/chat.h
+++ b/chat.h
@@ -125,7 +125,7 @@ struct Message {
};
void ircConfig(bool insecure, FILE *cert, FILE *priv);
-int ircConnect(const char *host, const char *port);
+int ircConnect(const char *bind, const char *host, const char *port);
void ircRecv(void);
void ircSend(const char *ptr, size_t len);
void ircFormat(const char *format, ...)
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;