IPv6 support for syslogd.

Reviewed by:	freebsd-current
Obtained from:	NetBSD
This commit is contained in:
ume 2000-12-16 18:25:48 +00:00
parent d046c56964
commit e4a876193f
3 changed files with 421 additions and 147 deletions

View File

@ -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>

View File

@ -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

View File

@ -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;
finet = socksetup(family);
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);
}
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)) {
@ -547,12 +564,38 @@ 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;
int masklen = -1;
struct addrinfo hints, *res;
struct in_addr *addrp, *maskp;
u_int32_t *mask6p;
char ip[NI_MAXHOST];
if ((cp1 = strrchr(s, ':'))) {
#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 */
ap.isnumeric = 1;
if ((cp1 = strchr(s, '/')) != NULL) {
*cp1++ = '\0';
i = atoi(cp1);
if (i < 0 || i > 32)
return -1;
/* convert masklen to netmask */
ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
}
if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
if ((cp1 = strchr(s, '/')) != NULL &&
strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
*cp1 = '\0';
if ((masklen = atoi(cp1 + 1)) < 0)
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);
}
#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;
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 */
while (masklen > 0) {
if (masklen < 32) {
*mask6p = htonl(~(0xffffffff >> masklen));
break;
}
*mask6p++ = 0xffffffff;
masklen -= 32;
}
}
#endif
else {
freeaddrinfo(res);
return -1;
}
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);
}