Author: hrs Date: Thu Dec 22 23:39:11 2016 New Revision: 310434 URL: https://svnweb.freebsd.org/changeset/base/310434
Log: - Add -S option to specify the source address/port for UDP communication. - Document -S option. - Document that -h option supports AF_LOCAL. - Split preparation of UDP sockets in logmessage() into socksetup(). Modified: head/usr.bin/logger/logger.1 head/usr.bin/logger/logger.c Modified: head/usr.bin/logger/logger.1 ============================================================================== --- head/usr.bin/logger/logger.1 Thu Dec 22 22:30:42 2016 (r310433) +++ head/usr.bin/logger/logger.1 Thu Dec 22 23:39:11 2016 (r310434) @@ -28,7 +28,7 @@ .\" @(#)logger.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd March 21, 2015 +.Dd December 23, 2016 .Dt LOGGER 1 .Os .Sh NAME @@ -41,6 +41,7 @@ .Op Fl h Ar host .Op Fl P Ar port .Op Fl p Ar pri +.Op Fl S Ar addr Ns \&: Ns Ar port .Op Fl t Ar tag .Op Ar message ... .Sh DESCRIPTION @@ -80,6 +81,28 @@ This option is ignored when a message is Send the message to the remote system .Ar host instead of logging it locally. +Note that +.Nm +currently supports +.Li AF_INET +.Pq IPv4 , +.Li AF_INET6 +.Pq IPv6 , +and +.Li AF_LOCAL +.Pq Unix-domain socket +address families. +The following address formats are valid in +.Ar host : +.Pp +.Bl -tag -width "AF_LOCAL" -compact +.It Li AF_INET +192.168.2.1 +.It Li AF_INET6 +2001:db8::1 +.It Li AF_LOCAL +.Pa /var/run/log +.El .It Fl P Ar port Send the message to the specified .Ar port @@ -101,6 +124,20 @@ level in the .Ar local3 facility. The default is ``user.notice.'' +.It Fl S Ar addr Ns \&: Ns Ar port +Specify source address and/or source port when using +.Fl h +option. +The same address will be used for all of the remote addresses +when +.Fl A +flag is enabled. +Note that a numeric IPv6 address in +.Ar addr +must be enclosed with +.Qq \&[ +and +.Qq \&] . .It Fl t Ar tag Mark every line in the log with the specified .Ar tag Modified: head/usr.bin/logger/logger.c ============================================================================== --- head/usr.bin/logger/logger.c Thu Dec 22 22:30:42 2016 (r310433) +++ head/usr.bin/logger/logger.c Thu Dec 22 23:39:11 2016 (r310434) @@ -57,18 +57,22 @@ __FBSDID("$FreeBSD$"); #define SYSLOG_NAMES #include <syslog.h> +#define sstosa(ss) ((struct sockaddr *)(void *)ss) + +struct socks { + int sk_sock; + int sk_addrlen; + struct sockaddr_storage sk_addr; +}; + static int decode(char *, const CODE *); static int pencode(char *); -static void logmessage(int, const char *, const char *, const char *, +static ssize_t socksetup(const char *, const char *, const char *, + struct socks **); +static void logmessage(int, const char *, struct socks *, ssize_t, const char *); static void usage(void); -struct socks { - int sock; - int addrlen; - struct sockaddr_storage addr; -}; - #ifdef INET6 static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ #else @@ -85,17 +89,20 @@ static int send_to_all = 0; /* send mess int main(int argc, char *argv[]) { + struct socks *socks; + ssize_t nsock; int ch, logflags, pri; char *tag, *host, buf[1024]; - const char *svcname; + const char *svcname, *src; tag = NULL; host = NULL; svcname = "syslog"; + src = NULL; pri = LOG_USER | LOG_NOTICE; logflags = 0; unsetenv("TZ"); - while ((ch = getopt(argc, argv, "46Af:h:iP:p:st:")) != -1) + while ((ch = getopt(argc, argv, "46Af:h:iP:p:S:st:")) != -1) switch((char)ch) { case '4': family = PF_INET; @@ -128,6 +135,9 @@ main(int argc, char *argv[]) case 's': /* log to standard error */ logflags |= LOG_PERROR; break; + case 'S': /* source address */ + src = optarg; + break; case 't': /* tag */ tag = optarg; break; @@ -138,6 +148,16 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + if (host) { + nsock = socksetup(src, host, svcname, &socks); + if (nsock <= 0) + errx(1, "socket"); + } else { + if (src) + errx(1, "-h option is missing."); + nsock = 0; + } + if (tag == NULL) tag = getlogin(); /* setup for logging */ @@ -153,11 +173,11 @@ main(int argc, char *argv[]) for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { len = strlen(*argv); if (p + len > endp && p > buf) { - logmessage(pri, tag, host, svcname, buf); + logmessage(pri, tag, socks, nsock, buf); p = buf; } if (len > sizeof(buf) - 1) - logmessage(pri, tag, host, svcname, *argv++); + logmessage(pri, tag, socks, nsock, *argv++); else { if (p != buf) *p++ = ' '; @@ -166,78 +186,162 @@ main(int argc, char *argv[]) } } if (p != buf) - logmessage(pri, tag, host, svcname, buf); + logmessage(pri, tag, socks, nsock, buf); } else while (fgets(buf, sizeof(buf), stdin) != NULL) - logmessage(pri, tag, host, svcname, buf); + logmessage(pri, tag, socks, nsock, buf); exit(0); } +static ssize_t +socksetup(const char *src, const char *dst, const char *svcname, + struct socks **socks) +{ + struct addrinfo hints, *res, *res0; + struct sockaddr_storage *ss_src[AF_MAX]; + struct socks *sk; + ssize_t nsock = 0; + int error, maxs; + + memset(&ss_src[0], 0, sizeof(ss_src)); + if (src) { + char *p, *p0, *hs, *hbuf, *sbuf; + + hbuf = sbuf = NULL; + p0 = p = strdup(src); + if (p0 == NULL) + err(1, "strdup failed"); + hs = p0; /* point to search ":" */ +#ifdef INET6 + /* -S option supports IPv6 addr in "[2001:db8::1]:service". */ + if (*p0 == '[') { + p = strchr(p0, ']'); + if (p == NULL) + errx(1, "\"]\" not found in src addr"); + *p = '\0'; + /* hs points just after ']' (':' or '\0'). */ + hs = p + 1; + /* + * p points just after '[' while it points hs + * in the case of []. + */ + p = ((p0 + 1) == (hs - 1)) ? hs : p0 + 1; + } +#endif + if (*p != '\0') { + /* (p == hs) means ":514" or "[]:514". */ + hbuf = (p == hs && *p == ':') ? NULL : p; + p = strchr(hs, ':'); + if (p != NULL) { + *p = '\0'; + sbuf = (*(p + 1) != '\0') ? p + 1 : NULL; + } + } + hints = (struct addrinfo){ + .ai_family = family, + .ai_socktype = SOCK_DGRAM, + .ai_flags = AI_PASSIVE + }; + error = getaddrinfo(hbuf, sbuf, &hints, &res0); + if (error) + errx(1, "%s: %s", gai_strerror(error), src); + for (res = res0; res; res = res->ai_next) { + switch (res->ai_family) { + case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif + if (ss_src[res->ai_family] != NULL) + continue; + ss_src[res->ai_family] = + malloc(sizeof(struct sockaddr_storage)); + if (ss_src[res->ai_family] == NULL) + err(1, "malloc failed"); + memcpy(ss_src[res->ai_family], res->ai_addr, + res->ai_addrlen); + } + } + freeaddrinfo(res0); + free(p0); + } + + /* resolve hostname */ + hints = (struct addrinfo){ + .ai_family = family, + .ai_socktype = SOCK_DGRAM + }; + error = getaddrinfo(dst, svcname, &hints, &res0); + if (error == EAI_SERVICE) { + warnx("%s/udp: unknown service", svcname); + error = getaddrinfo(dst, "514", &hints, &res); + } + if (error) + errx(1, "%s: %s", gai_strerror(error), dst); + /* count max number of sockets we may open */ + maxs = 0; + for (res = res0; res; res = res->ai_next) + maxs++; + sk = calloc(maxs, sizeof(*sk)); + if (sk == NULL) + errx(1, "couldn't allocate memory for sockets"); + for (res = res0; res; res = res->ai_next) { + int s; + + s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (s < 0) + continue; + if (src && ss_src[res->ai_family] == NULL) + errx(1, "address family mismatch"); + + if (ss_src[res->ai_family]) { + error = bind(s, sstosa(ss_src[res->ai_family]), + ss_src[res->ai_family]->ss_len); + if (error < 0) + err(1, "bind"); + } + sk[nsock] = (struct socks){ + .sk_addrlen = res->ai_addrlen, + .sk_sock = s + }; + memcpy(&sk[nsock].sk_addr, res->ai_addr, res->ai_addrlen); + nsock++; + } + freeaddrinfo(res0); + + *socks = sk; + return (nsock); +} + /* * Send the message to syslog, either on the local host, or on a remote host */ static void -logmessage(int pri, const char *tag, const char *host, const char *svcname, - const char *buf) +logmessage(int pri, const char *tag, struct socks *sk, ssize_t nsock, + const char *buf) { - static struct socks *socks; - static int nsock = 0; - struct addrinfo hints, *res, *r; char *line; - int maxs, len, sock, error, i, lsent; + int len, i, lsent; - if (host == NULL) { + if (nsock == 0) { syslog(pri, "%s", buf); return; } - - if (nsock <= 0) { /* set up socket stuff */ - /* resolve hostname */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_DGRAM; - error = getaddrinfo(host, svcname, &hints, &res); - if (error == EAI_SERVICE) { - warnx("%s/udp: unknown service", svcname); - error = getaddrinfo(host, "514", &hints, &res); - } - if (error) - errx(1, "%s: %s", gai_strerror(error), host); - /* count max number of sockets we may open */ - for (maxs = 0, r = res; r; r = r->ai_next, maxs++); - socks = malloc(maxs * sizeof(struct socks)); - if (!socks) - errx(1, "couldn't allocate memory for sockets"); - for (r = res; r; r = r->ai_next) { - sock = socket(r->ai_family, r->ai_socktype, - r->ai_protocol); - if (sock < 0) - continue; - memcpy(&socks[nsock].addr, r->ai_addr, r->ai_addrlen); - socks[nsock].addrlen = r->ai_addrlen; - socks[nsock++].sock = sock; - } - freeaddrinfo(res); - if (nsock <= 0) - errx(1, "socket"); - } - if ((len = asprintf(&line, "<%d>%s: %s", pri, tag, buf)) == -1) errx(1, "asprintf"); lsent = -1; - for (i = 0; i < nsock; ++i) { - lsent = sendto(socks[i].sock, line, len, 0, - (struct sockaddr *)&socks[i].addr, - socks[i].addrlen); + for (i = 0; i < nsock; i++) { + lsent = sendto(sk[i].sk_sock, line, len, 0, + sstosa(&sk[i].sk_addr), sk[i].sk_addrlen); if (lsent == len && !send_to_all) break; } if (lsent != len) { if (lsent == -1) - warn ("sendto"); + warn("sendto"); else - warnx ("sendto: short send - %d bytes", lsent); + warnx("sendto: short send - %d bytes", lsent); } free(line); @@ -290,7 +394,7 @@ usage(void) { (void)fprintf(stderr, "usage: %s\n", "logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n" - " [message ...]" + " [-S addr:port] [message ...]" ); exit(1); } _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"