summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2000-12-16 18:25:48 +0000
committerume <ume@FreeBSD.org>2000-12-16 18:25:48 +0000
commit6b337143f034c6c48c1be74de60562e248ba61b8 (patch)
treef60e0e40e84b9a2ce5cabda779c28242448b909f /usr.sbin
parentbd199e398300ffe7763db31037bf1a6d19b2d407 (diff)
downloadFreeBSD-src-6b337143f034c6c48c1be74de60562e248ba61b8.zip
FreeBSD-src-6b337143f034c6c48c1be74de60562e248ba61b8.tar.gz
IPv6 support for syslogd.
Reviewed by: freebsd-current Obtained from: NetBSD
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/syslogd/Makefile3
-rw-r--r--usr.sbin/syslogd/syslogd.834
-rw-r--r--usr.sbin/syslogd/syslogd.c527
3 files changed, 419 insertions, 145 deletions
diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile
index 8bac8b3..b137d46 100644
--- a/usr.sbin/syslogd/Makefile
+++ b/usr.sbin/syslogd/Makefile
@@ -1,10 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
PROG= syslogd
SRCS= syslogd.c ttymsg.c
.PATH: ${.CURDIR}/../../usr.bin/wall
MAN5= syslog.conf.5
MAN8= syslogd.8
-COPTS+= -Wall
+COPTS+= -Wall -DINET6
.include <bsd.prog.mk>
diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8
index c4a0a9e..a13a4a7 100644
--- a/usr.sbin/syslogd/syslogd.8
+++ b/usr.sbin/syslogd/syslogd.8
@@ -54,6 +54,21 @@ machines and/or users as specified by its configuration file.
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl A
+.Nm
+tries to send the message to only one address
+even if the host has more than one A or AAAA record.
+If this option is specified,
+.Nm
+tries to send the message to all addresses.
.It Fl a Ar allowed_peer
Allow
.Ar allowed_peer
@@ -71,8 +86,13 @@ Accept datagrams from
.Ar ipaddr
(in the usual dotted quad notation) with
.Ar masklen
-bits being taken into account when doing the address comparison. If
-specified,
+bits being taken into account when doing the address comparison.
+.Ar ipaddr
+can be also IPv6 address by enclosing the address with
+.Ql [
+and
+.Ql \&] .
+If specified,
.Ar service
is the name or number of an UDP service (see
.Xr services 5 ) Ns
@@ -84,12 +104,18 @@ allows packets being sent from any UDP port. The default
.Ar service
is
.Ql syslog .
-A missing
+If
+.Ar ipaddr
+is IPv4 address, a missing
.Ar masklen
will be substituted by the historic class A or class B netmasks if
.Ar ipaddr
belongs into the address range of class A or B, respectively, or
-by 24 otherwise.
+by 24 otherwise. If
+.Ar ipaddr
+is IPv6 address, a missing
+.Ar masklen
+will be substituted by 128.
.It Ar domainname Ns Op Ar :service
Accept datagrams where the reverse address lookup yields
.Ar domainname
diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c
index aa3c08a..09a150d 100644
--- a/usr.sbin/syslogd/syslogd.c
+++ b/usr.sbin/syslogd/syslogd.c
@@ -99,7 +99,6 @@ static const char rcsid[] =
#include <err.h>
#include <errno.h>
#include <fcntl.h>
-#include <regex.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
@@ -113,6 +112,12 @@ static const char rcsid[] =
#define SYSLOG_NAMES
#include <sys/syslog.h>
+#ifdef NI_WITHSCOPEID
+static const int withscopeid = NI_WITHSCOPEID;
+#else
+static const int withscopeid = 0;
+#endif
+
const char *ConfFile = _PATH_LOGCONF;
const char *PidFile = _PATH_LOGPID;
const char ctty[] = _PATH_CONSOLE;
@@ -158,7 +163,8 @@ struct filed {
char f_uname[MAXUNAMES][UT_NAMESIZE+1];
struct {
char f_hname[MAXHOSTNAMELEN+1];
- struct sockaddr_in f_addr;
+ struct addrinfo *f_addr;
+
} f_forw; /* forwarding address */
char f_fname[MAXPATHLEN];
struct {
@@ -208,8 +214,8 @@ struct allowedpeer {
u_short port;
union {
struct {
- struct in_addr addr;
- struct in_addr mask;
+ struct sockaddr_storage addr;
+ struct sockaddr_storage mask;
} numeric;
char *name;
} u;
@@ -253,13 +259,18 @@ int Debug; /* debug flag */
int resolve = 1; /* resolve hostname */
char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
char *LocalDomain; /* our local domain name */
-int finet = -1; /* Internet datagram socket */
+int *finet = NULL; /* Internet datagram socket */
int fklog = -1; /* /dev/klog */
-int LogPort; /* port number for INET connections */
int Initialized = 0; /* set when we have initialized ourselves */
int MarkInterval = 20 * 60; /* interval between marks in seconds */
int MarkSeq = 0; /* mark sequence number */
int SecureMode = 0; /* when true, receive only unix domain socks */
+#ifdef INET6
+int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
+#else
+int family = PF_INET; /* protocol family (IPv4 only) */
+#endif
+int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
char bootfile[MAXLINE+1]; /* booted kernel file */
@@ -273,13 +284,14 @@ int KeepKernFac = 0; /* Keep remotely logged kernel facility */
int allowaddr __P((char *));
void cfline __P((char *, struct filed *, char *, char *));
-char *cvthname __P((struct sockaddr_in *));
+char *cvthname __P((struct sockaddr *));
void deadq_enter __P((pid_t, const char *));
int deadq_remove __P((pid_t));
int decode __P((const char *, CODE *));
void die __P((int));
void domark __P((int));
void fprintlog __P((struct filed *, int, char *));
+int* socksetup __P((int));
void init __P((int));
void logerror __P((const char *));
void logmsg __P((int, char *, char *, int));
@@ -291,7 +303,8 @@ void readklog __P((void));
void reapchild __P((int));
char *ttymsg __P((struct iovec *, int, char *, int));
static void usage __P((void));
-int validate __P((struct sockaddr_in *, const char *));
+int validate __P((struct sockaddr *, const char *));
+static void unmapped __P((struct sockaddr *));
void wallmsg __P((struct filed *, struct iovec *));
int waitdaemon __P((int, int, int));
void timedout __P((int));
@@ -303,7 +316,7 @@ main(argc, argv)
{
int ch, i, l;
struct sockaddr_un sunx, fromunix;
- struct sockaddr_in sin, frominet;
+ struct sockaddr_storage frominet;
FILE *fp;
char *p, *hname, line[MAXLINE + 1];
struct timeval tv, *tvp;
@@ -312,8 +325,19 @@ main(argc, argv)
pid_t ppid = 1;
socklen_t len;
- while ((ch = getopt(argc, argv, "a:df:kl:m:np:suv")) != -1)
+ while ((ch = getopt(argc, argv, "46Aa:df:kl:m:np:suv")) != -1)
switch (ch) {
+ case '4':
+ family = PF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ family = PF_INET6;
+ break;
+#endif
+ case 'A':
+ send_to_all++;
+ break;
case 'a': /* allow specific network addresses only */
if (allowaddr(optarg) == -1)
usage();
@@ -420,32 +444,20 @@ main(argc, argv)
}
}
if (SecureMode <= 1)
- finet = socket(AF_INET, SOCK_DGRAM, 0);
- if (finet >= 0) {
- struct servent *sp;
-
- sp = getservbyname("syslog", "udp");
- if (sp == NULL) {
- errno = 0;
- logerror("syslog/udp: unknown service");
- die(0);
- }
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = LogPort = sp->s_port;
-
- if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- logerror("bind");
- if (!Debug)
- die(0);
- }
- }
- if (finet >= 0 && SecureMode) {
- if (shutdown(finet, SHUT_RD) < 0) {
- logerror("shutdown");
- if (!Debug)
- die(0);
- }
+ finet = socksetup(family);
+
+ if (finet) {
+ if (SecureMode) {
+ for (i = 0; i < *finet; i++) {
+ if (shutdown(finet[i+1], SHUT_RD) < 0) {
+ logerror("shutdown");
+ if (!Debug)
+ die(0);
+ }
+ }
+ } else
+ dprintf("listening on inet and/or inet6 socket\n");
+ dprintf("sending on inet and/or inet6 socket\n");
}
if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
@@ -485,10 +497,12 @@ main(argc, argv)
if (fklog > nfds)
nfds = fklog;
}
- if (finet != -1 && !SecureMode) {
- FD_SET(finet, &readfds);
- if (finet > nfds)
- nfds = finet;
+ if (finet && !SecureMode) {
+ for (i = 0; i < *finet; i++) {
+ FD_SET(finet[i+1], &readfds);
+ if (finet[i+1] > nfds)
+ nfds = finet[i+1];
+ }
}
for (i = 0; i < nfunix; i++) {
if (funix[i] != -1) {
@@ -517,20 +531,23 @@ main(argc, argv)
/*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/
if (fklog != -1 && FD_ISSET(fklog, &readfds))
readklog();
- if (finet != -1 && FD_ISSET(finet, &readfds)) {
- len = sizeof(frominet);
- l = recvfrom(finet, line, MAXLINE, 0,
- (struct sockaddr *)&frominet, &len);
- if (l > 0) {
- line[l] = '\0';
- if (resolve)
- hname = cvthname(&frominet);
- else
- hname = inet_ntoa(frominet.sin_addr);
- if (validate(&frominet, hname))
- printline(hname, line);
- } else if (l < 0 && errno != EINTR)
- logerror("recvfrom inet");
+ if (finet && !SecureMode) {
+ for (i = 0; i < *finet; i++) {
+ if (FD_ISSET(finet[i+1], &readfds)) {
+ len = sizeof(frominet);
+ l = recvfrom(finet[i+1], line, MAXLINE,
+ 0, (struct sockaddr *)&frominet,
+ &len);
+ if (l > 0) {
+ line[l] = '\0';
+ hname = cvthname((struct sockaddr *)&frominet);
+ unmapped((struct sockaddr *)&frominet);
+ if (validate((struct sockaddr *)&frominet, hname))
+ printline(hname, line);
+ } else if (l < 0 && errno != EINTR)
+ logerror("recvfrom inet");
+ }
+ }
}
for (i = 0; i < nfunix; i++) {
if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) {
@@ -548,11 +565,37 @@ main(argc, argv)
}
static void
+unmapped(sa)
+ struct sockaddr *sa;
+{
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in sin;
+
+ if (sa->sa_family != AF_INET6)
+ return;
+ if (sa->sa_len != sizeof(struct sockaddr_in6) ||
+ sizeof(sin) > sa->sa_len)
+ return;
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin.sin_addr));
+ sin.sin_port = sin6->sin6_port;
+
+ memcpy(sa, &sin, sin.sin_len);
+}
+
+static void
usage()
{
fprintf(stderr, "%s\n%s\n%s\n",
- "usage: syslogd [-dnsuv] [-a allowed_peer] [-f config_file]",
+ "usage: syslogd [-46Adnsuv] [-a allowed_peer] [-f config_file]",
" [-m mark_interval] [-p log_socket]",
" [-l log_socket]");
exit(1);
@@ -844,7 +887,8 @@ fprintlog(f, flags, msg)
{
struct iovec iov[7];
struct iovec *v;
- int l;
+ struct addrinfo *r;
+ int i, l, lsent = 0;
char line[MAXLINE + 1], repbuf[80], greetings[200];
char *msgret;
@@ -950,15 +994,33 @@ fprintlog(f, flags, msg)
f->f_prevpri, iov[0].iov_base, iov[5].iov_base);
if (l > MAXLINE)
l = MAXLINE;
- if ((finet >= 0) &&
- (sendto(finet, line, l, 0,
- (struct sockaddr *)&f->f_un.f_forw.f_addr,
- sizeof(f->f_un.f_forw.f_addr)) != l)) {
- int e = errno;
- (void)close(f->f_file);
- f->f_type = F_UNUSED;
- errno = e;
- logerror("sendto");
+
+ if (finet) {
+ for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
+ for (i = 0; i < *finet; i++) {
+#if 0
+ /*
+ * should we check AF first, or just
+ * trial and error? FWD
+ */
+ if (r->ai_family ==
+ address_family_of(finet[i+1]))
+#endif
+ lsent = sendto(finet[i+1], line, l, 0,
+ r->ai_addr, r->ai_addrlen);
+ if (lsent == l)
+ break;
+ }
+ if (lsent == l && !send_to_all)
+ break;
+ }
+ if (lsent != l) {
+ int e = errno;
+ (void)close(f->f_file);
+ errno = e;
+ f->f_type = F_UNUSED;
+ logerror("sendto");
+ }
}
break;
@@ -1124,33 +1186,41 @@ reapchild(signo)
*/
char *
cvthname(f)
- struct sockaddr_in *f;
+ struct sockaddr *f;
{
- struct hostent *hp;
+ int error;
sigset_t omask, nmask;
char *p;
+ static char hname[NI_MAXHOST], ip[NI_MAXHOST];
- dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
+ error = getnameinfo((struct sockaddr *)f,
+ ((struct sockaddr *)f)->sa_len,
+ ip, sizeof ip, NULL, 0,
+ NI_NUMERICHOST | withscopeid);
+ dprintf("cvthname(%s)\n", ip);
- if (f->sin_family != AF_INET) {
- dprintf("Malformed from address\n");
+ if (error) {
+ dprintf("Malformed from address %s\n", gai_strerror(error));
return ("???");
}
+ if (!resolve)
+ return (ip);
+
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
sigprocmask(SIG_BLOCK, &nmask, &omask);
- hp = gethostbyaddr((char *)&f->sin_addr,
- sizeof(struct in_addr), f->sin_family);
+ error = getnameinfo((struct sockaddr *)f,
+ ((struct sockaddr *)f)->sa_len,
+ hname, sizeof hname, NULL, 0,
+ NI_NAMEREQD | withscopeid);
sigprocmask(SIG_SETMASK, &omask, NULL);
- if (hp == 0) {
- dprintf("Host name for your address (%s) unknown\n",
- inet_ntoa(f->sin_addr));
- return (inet_ntoa(f->sin_addr));
+ if (error) {
+ dprintf("Host name for your address (%s) unknown\n", ip);
+ return (ip);
}
- if ((p = strchr(hp->h_name, '.')) &&
- strcasecmp(p + 1, LocalDomain) == 0)
+ if ((p = strchr(hname, '.')) && strcasecmp(p + 1, LocalDomain) == 0)
*p = '\0';
- return (hp->h_name);
+ return (hname);
}
void
@@ -1434,8 +1504,8 @@ cfline(line, f, prog, host)
char *prog;
char *host;
{
- struct hostent *hp;
- int i, pri;
+ struct addrinfo hints, *res;
+ int error, i, pri;
char *bp, *p, *q;
char buf[MAXLINE], ebuf[100];
@@ -1558,18 +1628,17 @@ cfline(line, f, prog, host)
case '@':
(void)strncpy(f->f_un.f_forw.f_hname, ++p,
sizeof(f->f_un.f_forw.f_hname)-1);
- f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';
- hp = gethostbyname(f->f_un.f_forw.f_hname);
- if (hp == NULL) {
-
- logerror(hstrerror(h_errno));
+ f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0';
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
+ &res);
+ if (error) {
+ logerror(gai_strerror(error));
break;
}
- memset(&f->f_un.f_forw.f_addr, 0,
- sizeof(f->f_un.f_forw.f_addr));
- f->f_un.f_forw.f_addr.sin_family = AF_INET;
- f->f_un.f_forw.f_addr.sin_port = LogPort;
- memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
+ f->f_un.f_forw.f_addr = res;
f->f_type = F_FORW;
break;
@@ -1741,76 +1810,136 @@ allowaddr(s)
char *cp1, *cp2;
struct allowedpeer ap;
struct servent *se;
- regex_t re;
- int i;
-
- if ((cp1 = strrchr(s, ':'))) {
+ int masklen = -1;
+ struct addrinfo hints, *res;
+ struct in_addr *addrp, *maskp;
+ u_int32_t *mask6p;
+ char ip[NI_MAXHOST];
+
+#ifdef INET6
+ if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
+#endif
+ cp1 = s;
+ if ((cp1 = strrchr(cp1, ':'))) {
/* service/port provided */
*cp1++ = '\0';
if (strlen(cp1) == 1 && *cp1 == '*')
/* any port allowed */
- ap.port = htons(0);
+ ap.port = 0;
else if ((se = getservbyname(cp1, "udp")))
- ap.port = se->s_port;
+ ap.port = ntohs(se->s_port);
else {
- ap.port = htons((int)strtol(cp1, &cp2, 0));
+ ap.port = strtol(cp1, &cp2, 0);
if (*cp2 != '\0')
return -1; /* port not numeric */
}
} else {
if ((se = getservbyname("syslog", "udp")))
- ap.port = se->s_port;
+ ap.port = ntohs(se->s_port);
else
/* sanity, should not happen */
- ap.port = htons(514);
+ ap.port = 514;
}
- /* the regexp's are ugly, but the cleanest way */
-
- if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$",
- REG_EXTENDED))
- /* if RE compilation fails, that's an internal error */
- abort();
- if (regexec(&re, s, 0, 0, 0) == 0) {
- /* arg `s' is numeric */
+ if ((cp1 = strchr(s, '/')) != NULL &&
+ strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
+ *cp1 = '\0';
+ if ((masklen = atoi(cp1 + 1)) < 0)
+ return -1;
+ }
+#ifdef INET6
+ if (*s == '[') {
+ cp2 = s + strlen(s) - 1;
+ if (*cp2 == ']') {
+ ++s;
+ *cp2 = '\0';
+ } else
+ cp2 = NULL;
+ } else
+ cp2 = NULL;
+#endif
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+ if (getaddrinfo(s, NULL, &hints, &res) == 0) {
ap.isnumeric = 1;
- if ((cp1 = strchr(s, '/')) != NULL) {
- *cp1++ = '\0';
- i = atoi(cp1);
- if (i < 0 || i > 32)
+ memcpy(&ap.a_addr, res->ai_addr, res->ai_addrlen);
+ memset(&ap.a_mask, 0, sizeof(ap.a_mask));
+ ap.a_mask.ss_family = res->ai_family;
+ if (res->ai_family == AF_INET) {
+ ap.a_mask.ss_len = sizeof(struct sockaddr_in);
+ maskp = &((struct sockaddr_in *)&ap.a_mask)->sin_addr;
+ if (masklen < 0) {
+ /* use default netmask */
+ addrp = &((struct sockaddr_in *)&ap.a_addr)->sin_addr;
+ if (IN_CLASSA(ntohl(addrp->s_addr)))
+ maskp->s_addr = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(addrp->s_addr)))
+ maskp->s_addr = htonl(IN_CLASSB_NET);
+ else
+ maskp->s_addr = htonl(IN_CLASSC_NET);
+ } else if (masklen <= 32) {
+ /* convert masklen to netmask */
+ maskp->s_addr = htonl(~((1 << (32 - masklen)) - 1));
+ } else {
+ freeaddrinfo(res);
return -1;
+ }
+ }
+#ifdef INET6
+ else if (res->ai_family == AF_INET6 && masklen <= 128) {
+ ap.a_mask.ss_len = sizeof(struct sockaddr_in6);
+ if (masklen < 0)
+ masklen = 128;
+ mask6p = (u_int32_t *)&((struct sockaddr_in6 *)&ap.a_mask)->sin6_addr;
/* convert masklen to netmask */
- ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
+ while (masklen > 0) {
+ if (masklen < 32) {
+ *mask6p = htonl(~(0xffffffff >> masklen));
+ break;
+ }
+ *mask6p++ = 0xffffffff;
+ masklen -= 32;
+ }
}
- if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
+#endif
+ else {
+ freeaddrinfo(res);
return -1;
- if (cp1 == NULL) {
- /* use default netmask */
- if (IN_CLASSA(ntohl(ap.a_addr.s_addr)))
- ap.a_mask.s_addr = htonl(IN_CLASSA_NET);
- else if (IN_CLASSB(ntohl(ap.a_addr.s_addr)))
- ap.a_mask.s_addr = htonl(IN_CLASSB_NET);
- else
- ap.a_mask.s_addr = htonl(IN_CLASSC_NET);
}
+ freeaddrinfo(res);
} else {
/* arg `s' is domain name */
ap.isnumeric = 0;
ap.a_name = s;
+ if (cp1)
+ *cp1 = '/';
+#ifdef INET6
+ if (cp2) {
+ *cp2 = ']';
+ --s;
+ }
+#endif
}
- regfree(&re);
if (Debug) {
printf("allowaddr: rule %d: ", NumAllowed);
if (ap.isnumeric) {
printf("numeric, ");
- printf("addr = %s, ",
- addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0));
- printf("mask = %s; ",
- addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0));
+ getnameinfo((struct sockaddr *)&ap.a_addr,
+ ((struct sockaddr *)&ap.a_addr)->sa_len,
+ ip, sizeof ip, NULL, 0,
+ NI_NUMERICHOST | withscopeid);
+ printf("addr = %s, ", ip);
+ getnameinfo((struct sockaddr *)&ap.a_mask,
+ ((struct sockaddr *)&ap.a_mask)->sa_len,
+ ip, sizeof ip, NULL, 0,
+ NI_NUMERICHOST | withscopeid);
+ printf("mask = %s; ", ip);
} else
printf("domainname = %s; ", ap.a_name);
- printf("port = %d\n", ntohs(ap.port));
+ printf("port = %d\n", ap.port);
}
if ((AllowedPeers = realloc(AllowedPeers,
@@ -1827,41 +1956,91 @@ allowaddr(s)
* Validate that the remote peer has permission to log to us.
*/
int
-validate(sin, hname)
- struct sockaddr_in *sin;
+validate(sa, hname)
+ struct sockaddr *sa;
const char *hname;
{
- int i;
+ int i, j, reject;
size_t l1, l2;
- char *cp, name[MAXHOSTNAMELEN];
+ char *cp, name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
struct allowedpeer *ap;
+ struct sockaddr_in *sin, *a4p = NULL, *m4p = NULL;
+ struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
+ struct addrinfo hints, *res;
+ u_short sport;
if (NumAllowed == 0)
/* traditional behaviour, allow everything */
return 1;
strlcpy(name, hname, sizeof name);
- if (strchr(name, '.') == NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+ if (getaddrinfo(name, NULL, &hints, &res) == 0)
+ freeaddrinfo(res);
+ else if (strchr(name, '.') == NULL) {
strlcat(name, ".", sizeof name);
strlcat(name, LocalDomain, sizeof name);
}
- dprintf("validate: dgram from IP %s, port %d, name %s;\n",
- addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0),
- ntohs(sin->sin_port), name);
+ if (getnameinfo(sa, sa->sa_len, ip, sizeof ip, port, sizeof port,
+ NI_NUMERICHOST | withscopeid | NI_NUMERICSERV) != 0)
+ return 0; /* for safety, should not occur */
+ dprintf("validate: dgram from IP %s, port %s, name %s;\n",
+ ip, port, name);
+ sport = atoi(port);
/* now, walk down the list */
for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
- if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) {
+ if (ap->port != 0 && ap->port != sport) {
dprintf("rejected in rule %d due to port mismatch.\n", i);
continue;
}
if (ap->isnumeric) {
- if ((sin->sin_addr.s_addr & ap->a_mask.s_addr)
- != ap->a_addr.s_addr) {
- dprintf("rejected in rule %d due to IP mismatch.\n", i);
+ if (ap->a_addr.ss_family != sa->sa_family) {
+ dprintf("rejected in rule %d due to address family mismatch.\n", i);
continue;
}
+ if (ap->a_addr.ss_family == AF_INET) {
+ sin = (struct sockaddr_in *)sa;
+ a4p = (struct sockaddr_in *)&ap->a_addr;
+ m4p = (struct sockaddr_in *)&ap->a_mask;
+ if ((sin->sin_addr.s_addr & m4p->sin_addr.s_addr)
+ != a4p->sin_addr.s_addr) {
+ dprintf("rejected in rule %d due to IP mismatch.\n", i);
+ continue;
+ }
+ }
+#ifdef INET6
+ else if (ap->a_addr.ss_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)sa;
+ a6p = (struct sockaddr_in6 *)&ap->a_addr;
+ m6p = (struct sockaddr_in6 *)&ap->a_mask;
+#ifdef NI_WITHSCOPEID
+ if (a6p->sin6_scope_id != 0 &&
+ sin6->sin6_scope_id != a6p->sin6_scope_id) {
+ dprintf("rejected in rule %d due to scope mismatch.\n", i);
+ continue;
+ }
+#endif
+ reject = 0;
+ for (j = 0; j < 16; j += 4) {
+ if ((*(u_int32_t *)&sin6->sin6_addr.s6_addr[i] & *(u_int32_t *)&m6p->sin6_addr.s6_addr[i])
+ != *(u_int32_t *)&a6p->sin6_addr.s6_addr[i]) {
+ ++reject;
+ break;
+ }
+ }
+ if (reject) {
+ dprintf("rejected in rule %d due to IP mismatch.\n", i);
+ continue;
+ }
+ }
+#endif
+ else
+ continue;
} else {
cp = ap->a_name;
l1 = strlen(name);
@@ -2044,3 +2223,71 @@ log_deadchild(pid, status, name)
pid, name, reason, code);
logerror(buf);
}
+
+int *
+socksetup(af)
+ int af;
+{
+ struct addrinfo hints, *res, *r;
+ int error, maxs, *s, *socks;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(NULL, "syslog", &hints, &res);
+ if (error) {
+ logerror(gai_strerror(error));
+ errno = 0;
+ die(0);
+ }
+
+ /* Count max number of sockets we may open */
+ for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
+ socks = malloc((maxs+1) * sizeof(int));
+ if (!socks) {
+ logerror("couldn't allocate memory for sockets");
+ die(0);
+ }
+
+ *socks = 0; /* num of sockets counter at start of array */
+ s = socks + 1;
+ for (r = res; r; r = r->ai_next) {
+ *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if (*s < 0) {
+ logerror("socket");
+ continue;
+ }
+#ifdef IPV6_BINDV6ONLY
+ if (r->ai_family == AF_INET6) {
+ int on = 1;
+ if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char *)&on, sizeof (on)) < 0) {
+ logerror("setsockopt");
+ close(*s);
+ continue;
+ }
+ }
+#endif
+ if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
+ close(*s);
+ logerror("bind");
+ continue;
+ }
+
+ (*socks)++;
+ s++;
+ }
+
+ if (*socks == 0) {
+ free(socks);
+ if (Debug)
+ return(NULL);
+ else
+ die(0);
+ }
+ if (res)
+ freeaddrinfo(res);
+
+ return(socks);
+}
OpenPOWER on IntegriCloud