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.
weechat-hashes
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 C Ar copy
.Op Fl H Ar hash .Op Fl H Ar hash
.Op Fl O Ar open .Op Fl O Ar open
.Op Fl S Ar bind
.Op Fl a Ar auth .Op Fl a Ar auth
.Op Fl c Ar cert .Op Fl c Ar cert
.Op Fl h Ar host .Op Fl h Ar host
@ -85,6 +86,11 @@ Disable the
.Ic /quote .Ic /quote
commands. 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 .It Fl a Ar user Ns : Ns Ar pass , Cm sasl-plain = Ar user Ns : Ns Ar pass
Authenticate as Authenticate as
.Ar user .Ar user

7
chat.c
View File

@ -82,6 +82,7 @@ int main(int argc, char *argv[]) {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
bool insecure = false; bool insecure = false;
const char *bind = NULL;
const char *host = NULL; const char *host = NULL;
const char *port = "6697"; const char *port = "6697";
const char *cert = NULL; const char *cert = NULL;
@ -93,13 +94,14 @@ int main(int argc, char *argv[]) {
const char *user = NULL; const char *user = NULL;
const char *real = 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[] = { const struct option LongOpts[] = {
{ "insecure", no_argument, NULL, '!' }, { "insecure", no_argument, NULL, '!' },
{ "copy", required_argument, NULL, 'C' }, { "copy", required_argument, NULL, 'C' },
{ "hash", required_argument, NULL, 'H' }, { "hash", required_argument, NULL, 'H' },
{ "open", required_argument, NULL, 'O' }, { "open", required_argument, NULL, 'O' },
{ "restrict", no_argument, NULL, 'R' }, { "restrict", no_argument, NULL, 'R' },
{ "bind", required_argument, NULL, 'S' },
{ "sasl-plain", required_argument, NULL, 'a' }, { "sasl-plain", required_argument, NULL, 'a' },
{ "cert", required_argument, NULL, 'c' }, { "cert", required_argument, NULL, 'c' },
{ "sasl-external", no_argument, NULL, 'e' }, { "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 'H': hashInit = strtoul(optarg, NULL, 0);
break; case 'O': utilPush(&urlOpenUtil, optarg); break; case 'O': utilPush(&urlOpenUtil, optarg);
break; case 'R': self.restricted = true; break; case 'R': self.restricted = true;
break; case 'S': bind = optarg;
break; case 'a': sasl = true; self.plain = optarg; break; case 'a': sasl = true; self.plain = optarg;
break; case 'c': cert = optarg; break; case 'c': cert = optarg;
break; case 'e': sasl = true; break; case 'e': sasl = true;
@ -182,7 +185,7 @@ int main(int argc, char *argv[]) {
uiFormat(Network, Cold, NULL, "Traveling..."); uiFormat(Network, Cold, NULL, "Traveling...");
uiDraw(); uiDraw();
int irc = ircConnect(host, port); int irc = ircConnect(bind, host, port);
if (pass) ircFormat("PASS :%s\r\n", pass); if (pass) ircFormat("PASS :%s\r\n", pass);
if (sasl) ircFormat("CAP REQ :sasl\r\n"); if (sasl) ircFormat("CAP REQ :sasl\r\n");
ircFormat("CAP LS\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); 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 ircRecv(void);
void ircSend(const char *ptr, size_t len); void ircSend(const char *ptr, size_t len);
void ircFormat(const char *format, ...) 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); 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); assert(client);
int error;
int sock = -1;
struct addrinfo *head; struct addrinfo *head;
struct addrinfo hints = { struct addrinfo hints = {
.ai_family = AF_UNSPEC, .ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM, .ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP, .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) { for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0) err(EX_OSERR, "socket"); 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); error = connect(sock, ai->ai_addr, ai->ai_addrlen);
if (!error) break; if (!error) break;