Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Dec 2016 23:39:12 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310434 - head/usr.bin/logger
Message-ID:  <201612222339.uBMNdCGf004704@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612222339.uBMNdCGf004704>