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"

Reply via email to