📄 daemon.c
字号:
{
addr.sin6.sin6_family = AF_INET6;
addr.sin6.sin6_addr = hid6.sin6_addr;
}
else
# endif /* NETINET6 */
{
/* try it as a host name (avoid MX lookup) */
hp = sm_gethostbyname(&host[1], family);
if (hp == NULL && p[-1] == '.')
{
# if NAMED_BIND
int oldopts = _res.options;
_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
# endif /* NAMED_BIND */
p[-1] = '\0';
hp = sm_gethostbyname(&host[1],
family);
p[-1] = '.';
# if NAMED_BIND
_res.options = oldopts;
# endif /* NAMED_BIND */
}
*p = ']';
goto gothostent;
}
*p = ']';
}
if (p == NULL)
{
extern char MsgBuf[];
usrerrenh("5.1.2",
"553 Invalid numeric domain spec \"%s\"",
host);
mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
errno = EINVAL;
return EX_NOHOST;
}
}
else
{
/* contortion to get around SGI cc complaints */
{
p = &host[strlen(host) - 1];
hp = sm_gethostbyname(host, family);
if (hp == NULL && *p == '.')
{
# if NAMED_BIND
int oldopts = _res.options;
_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
# endif /* NAMED_BIND */
*p = '\0';
hp = sm_gethostbyname(host, family);
*p = '.';
# if NAMED_BIND
_res.options = oldopts;
# endif /* NAMED_BIND */
}
}
gothostent:
if (hp == NULL)
{
# if NAMED_BIND
/* check for name server timeouts */
if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
(errno == ECONNREFUSED && UseNameServer))
{
save_errno = errno;
mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
errno = save_errno;
return EX_TEMPFAIL;
}
# endif /* NAMED_BIND */
# if NETINET6
/*
** Try v6 first, then fall back to v4.
** If we found a v6 address, but no v4
** addresses, then TEMPFAIL.
*/
if (family == AF_INET6)
{
family = AF_INET;
goto v4retry;
}
if (v6found)
goto v6tempfail;
# endif /* NETINET6 */
save_errno = errno;
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = save_errno;
return EX_NOHOST;
}
addr.sa.sa_family = hp->h_addrtype;
switch (hp->h_addrtype)
{
# if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr,
INADDRSZ);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr,
IN6ADDRSZ);
break;
# endif /* NETINET6 */
default:
if (hp->h_length > sizeof addr.sa.sa_data)
{
syserr("makeconnection: long sa_data: family %d len %d",
hp->h_addrtype, hp->h_length);
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = EINVAL;
return EX_NOHOST;
}
memmove(addr.sa.sa_data,
hp->h_addr,
hp->h_length);
break;
}
addrno = 1;
}
/*
** Determine the port number.
*/
if (port == 0)
{
# ifdef NO_GETSERVBYNAME
port = htons(25);
# else /* NO_GETSERVBYNAME */
register struct servent *sp = getservbyname("smtp", "tcp");
if (sp == NULL)
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, NOQID,
"makeconnection: service \"smtp\" unknown");
port = htons(25);
}
else
port = sp->s_port;
# endif /* NO_GETSERVBYNAME */
}
switch (addr.sa.sa_family)
{
# if NETINET
case AF_INET:
addr.sin.sin_port = port;
addrlen = sizeof (struct sockaddr_in);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
addr.sin6.sin6_port = port;
addrlen = sizeof (struct sockaddr_in6);
break;
# endif /* NETINET6 */
# if NETISO
case AF_ISO:
/* assume two byte transport selector */
memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
addrlen = sizeof (struct sockaddr_iso);
break;
# endif /* NETISO */
default:
syserr("Can't connect to address family %d", addr.sa.sa_family);
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = EINVAL;
return EX_NOHOST;
}
/*
** Try to actually open the connection.
*/
# ifdef XLA
/* if too many connections, don't bother trying */
if (!xla_noqueue_ok(host))
return EX_TEMPFAIL;
# endif /* XLA */
firstconnect = TRUE;
for (;;)
{
if (tTd(16, 1))
dprintf("makeconnection (%s [%s])\n",
host, anynet_ntoa(&addr));
/* save for logging */
CurHostAddr = addr;
if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
{
int rport = IPPORT_RESERVED - 1;
s = rresvport(&rport);
}
else
{
s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
}
if (s < 0)
{
save_errno = errno;
syserr("makeconnection: cannot create socket");
# ifdef XLA
xla_host_end(host);
# endif /* XLA */
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
errno = save_errno;
return EX_TEMPFAIL;
}
# ifdef SO_SNDBUF
if (TcpSndBufferSize > 0)
{
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
(char *) &TcpSndBufferSize,
sizeof(TcpSndBufferSize)) < 0)
syserr("makeconnection: setsockopt(SO_SNDBUF)");
}
# endif /* SO_SNDBUF */
# ifdef SO_RCVBUF
if (TcpRcvBufferSize > 0)
{
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
(char *) &TcpRcvBufferSize,
sizeof(TcpRcvBufferSize)) < 0)
syserr("makeconnection: setsockopt(SO_RCVBUF)");
}
# endif /* SO_RCVBUF */
if (tTd(16, 1))
dprintf("makeconnection: fd=%d\n", s);
/* turn on network debugging? */
if (tTd(16, 101))
{
int on = 1;
(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
(char *)&on, sizeof on);
}
if (e->e_xfp != NULL)
(void) fflush(e->e_xfp); /* for debugging */
errno = 0; /* for debugging */
if (clt_bind)
{
int on = 1;
switch (clt_addr.sa.sa_family)
{
# if NETINET
case AF_INET:
if (clt_addr.sin.sin_port != 0)
(void) setsockopt(s, SOL_SOCKET,
SO_REUSEADDR,
(char *) &on,
sizeof on);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
if (clt_addr.sin6.sin6_port != 0)
(void) setsockopt(s, SOL_SOCKET,
SO_REUSEADDR,
(char *) &on,
sizeof on);
break;
# endif /* NETINET6 */
}
if (bind(s, &clt_addr.sa, socksize) < 0)
{
save_errno = errno;
(void) close(s);
errno = save_errno;
syserr("makeconnection: cannot bind socket [%s]",
anynet_ntoa(&clt_addr));
errno = save_errno;
return EX_TEMPFAIL;
}
}
/*
** Linux seems to hang in connect for 90 minutes (!!!).
** Time out the connect to avoid this problem.
*/
if (setjmp(CtxConnectTimeout) == 0)
{
int i;
if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
else if (TimeOuts.to_connect != 0)
ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
else
ev = NULL;
switch (ConnectOnlyTo.sa.sa_family)
{
# if NETINET
case AF_INET:
addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
&ConnectOnlyTo.sin6.sin6_addr,
IN6ADDRSZ);
break;
# endif /* NETINET6 */
}
i = connect(s, (struct sockaddr *) &addr, addrlen);
save_errno = errno;
if (ev != NULL)
clrevent(ev);
if (i >= 0)
break;
}
else
save_errno = errno;
/* if running demand-dialed connection, try again */
if (DialDelay > 0 && firstconnect)
{
if (tTd(16, 1))
dprintf("Connect failed (%s); trying again...\n",
errstring(save_errno));
firstconnect = FALSE;
(void) sleep(DialDelay);
continue;
}
/* couldn't connect.... figure out why */
(void) close(s);
if (LogLevel >= 14)
sm_syslog(LOG_INFO, e->e_id,
"makeconnection (%s [%s]) failed: %s",
host, anynet_ntoa(&addr),
errstring(save_errno));
if (hp != NULL && hp->h_addr_list[addrno] != NULL)
{
if (tTd(16, 1))
dprintf("Connect failed (%s); trying new address....\n",
errstring(save_errno));
switch (addr.sa.sa_family)
{
# if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr_list[addrno++],
INADDRSZ);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr_list[addrno++],
IN6ADDRSZ);
break;
# endif /* NETINET6 */
default:
memmove(addr.sa.sa_data,
hp->h_addr_list[addrno++],
hp->h_length);
break;
}
continue;
}
errno = save_errno;
# if NETINET6
if (family == AF_INET6)
{
if (tTd(16, 1))
dprintf("Connect failed (%s); retrying with AF_INET....\n",
errstring(save_errno));
v6found = TRUE;
family = AF_INET;
goto v4retry;
}
v6tempfail:
# endif /* NETINET6 */
/* couldn't open connection */
# if NETINET6
/* Don't clobber an already saved errno from v4retry */
if (errno > 0)
# endif /* NETINET6 */
save_errno = errno;
if (tTd(16, 1))
dprintf("Connect failed (%s)\n", errstring(save_errno));
# ifdef XLA
xla_host_end(host);
# endif /* XLA */
mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
errno = save_errno;
return EX_TEMPFAIL;
}
/* connection ok, put it into canonical form */
mci->mci_out = NULL;
if ((mci->mci_out = fdopen(s, "w")) == NULL ||
(s = dup(s)) < 0 ||
(mci->mci_in = fdopen(s, "r")) == NULL)
{
save_errno = errno;
syserr("cannot open SMTP client channel, fd=%d", s);
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
if (mci->mci_out != NULL)
(void) fclose(mci->mci_out);
(void) close(s);
errno = save_errno;
return EX_TEMPFAIL;
}
/* find out name for Interface through which we connect */
len = sizeof addr;
if (getsockname(s, &addr.sa, &len) == 0)
{
char *name;
char *p;
define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)),
&BlankEnvelope);
p = xalloc(5);
snprintf(p, 4, "%d", addr.sa.sa_family);
define(macid("{if_family}", NULL), p, &BlankEnvelope);
name = hostnamebyanyaddr(&addr);
define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope);
if (LogLevel > 11)
{
/* log connection information */
sm_syslog(LOG_INFO, e->e_id,
"SMTP outgoing connect on %.40s", name);
}
if (bitnset(D_IFNHELO, d_flags))
{
if (name[0] != '[' && strchr(name, '.') != NULL)
mci->mci_heloname = newstr(name);
}
}
else
{
define(macid("{if_name}", NULL), NULL, &BlankEnvelope);
define(macid("{if_addr}", NULL), NULL, &BlankEnvelope);
define(macid("{if_family}", NULL), NULL, &BlankEnvelope);
}
mci_setstat(mci, EX_OK, NULL, NULL);
return EX_OK;
}
static void
connecttimeout()
{
errno = ETIMEDOUT;
longjmp(CtxConnectTimeout, 1);
}
/*
** MAKECONNECTION_DS -- make a connection to a domain socket.
**
** Parameters:
** mux_path -- the path of the socket to connect to.
** mci -- a pointer to the mail connection information
** structure to be filled in.
**
** Returns:
** An exit code telling whether the connection could be
** made and if not why not.
**
** Side Effects:
** none.
*/
# if NETUNIX
int makeconnection_ds(mux_path, mci)
char *mux_path;
register MCI *mci;
{
int sock;
int rval, save_errno;
long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
struct sockaddr_un unix_addr;
/* if not safe, don't connect */
rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
sff, S_IRUSR|S_IWUSR, NULL);
if (rval != 0)
{
syserr("makeconnection_ds: unsafe domain socket");
mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
errno = rval;
return EX_TEMPFAIL;
}
/* prepare address structure */
memset(&unix_addr, '\0', sizeof unix_addr);
unix_addr.sun_family = AF_UNIX;
if (strlen(mux_path) >= sizeof unix_addr.sun_path)
{
syserr("makeconnection_ds: domain socket name too long");
/* XXX why TEMPFAIL ? */
mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
errno = ENAMETOOLONG;
return EX_UNAVAILABLE;
}
(void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path);
/* initialize domain socket */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
{
save_errno = errno;
syserr("makeconnection_ds: could not create domain socket");
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
errno = save_errno;
return EX_TEMPFAIL;
}
/* connect to server */
if (connect(sock, (struct sockaddr *) &unix_addr,
sizeof(unix_addr)) == -1)
{
save_errno = errno;
syserr("Could not connect to socket %s", mux_path);
mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
(void) close(sock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -