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.
master
multiplexd 2020-02-12 01:02:37 +00:00 committed by C. McEnroe
parent 489df70c37
commit 1e544ce482
4 changed files with 42 additions and 8 deletions

View File

@ -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

7
chat.c
View File

@ -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");

2
chat.h
View File

@ -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, ...)

33
irc.c
View File

@ -97,23 +97,48 @@ 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 (error) errx(EX_NOHOST, "%s:%s: %s", host, port, gai_strerror(error));
int sock = -1;
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));
for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
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;