2 * This code is copyright 2001 by Craig Hughes
3 * Portions copyright 2002 by Brad Jorsch
4 * It is licensed under the same license as Perl itself. The text of this
5 * license is included in the SpamAssassin distribution in the file named
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22 #include <arpa/inet.h>
24 #ifdef HAVE_SYSEXITS_H
30 #ifdef HAVE_SYS_ERRNO_H
31 #include <sys/errno.h>
36 #ifdef HAVE_SYS_TIME_H
40 #define MAX_CONNECT_RETRIES 3
41 #define CONNECT_RETRY_SLEEP 1
43 /* RedHat 5.2 doesn't define Shutdown 2nd Parameter Constants */
46 #define SHUT_RD (0) /* No more receptions. */
47 #define SHUT_WR (1) /* No more transmissions. */
48 #define SHUT_RDWR (2) /* No more receptions or transmissions. */
59 #ifndef HAVE_INADDR_NONE
60 #define INADDR_NONE ((in_addr_t) 0xffffffff)
63 /* jm: turned off for now, it should not be necessary. */
64 #undef USE_TCP_NODELAY
67 /* jm: very conservative figure, should be well out of range on almost all NIXes */
71 #undef DO_CONNECT_DEBUG_SYSLOGS
72 /* or #define DO_CONNECT_DEBUG_SYSLOGS 1 */
74 static const int ESC_PASSTHROUGHRAW = EX__MAX+666;
76 /* set EXPANSION_ALLOWANCE to something more than might be
77 added to a message in X-headers and the report template */
78 static const int EXPANSION_ALLOWANCE = 16384;
80 /* set NUM_CHECK_BYTES to number of bytes that have to match at beginning and end
81 of the data streams before and after processing by spamd
82 Aug 7 2002 jm: no longer seems to be used
83 static const int NUM_CHECK_BYTES = 32;
86 /* Set the protocol version that this spamc speaks */
87 static const char *PROTOCOL_VERSION="SPAMC/1.3";
89 int libspamc_timeout = 0;
92 try_to_connect (const struct sockaddr *argaddr, struct hostent *hent,
93 int hent_port, int *sockptr)
95 #ifdef USE_TCP_NODELAY
103 struct sockaddr_in addrbuf, *addr;
104 struct in_addr inaddrlist[256];
106 #ifdef DO_CONNECT_DEBUG_SYSLOGS
107 int dbgiter; char dbgbuf[2048]; int dbgbuflen = 0;
110 /* NOTE: do not call syslog() (unless you are about to return) before
111 * we take a copy of the h_addr_list.
114 /* only one set of connection targets can be used. assert this */
115 if (argaddr == NULL && hent == NULL) {
116 syslog (LOG_ERR, "oops! both NULL in try_to_connect");
118 } else if (argaddr != NULL && hent != NULL) {
119 syslog (LOG_ERR, "oops! both non-NULL in try_to_connect");
123 /* take a copy of the h_addr_list part of the struct hostent */
125 memset (inaddrlist, 0, sizeof(inaddrlist));
127 for (hostnum=0; hent->h_addr_list[hostnum] != 0; hostnum++) {
129 #ifdef DO_CONNECT_DEBUG_SYSLOGS
130 dbgbuflen += snprintf (dbgbuf+dbgbuflen, 2047-dbgbuflen,
131 "[%d %lx: %d.%d.%d.%d]",
132 hostnum, hent->h_addr_list[hostnum],
133 hent->h_addr_list[hostnum][0],
134 hent->h_addr_list[hostnum][1],
135 hent->h_addr_list[hostnum][2],
136 hent->h_addr_list[hostnum][3]);
140 syslog (LOG_ERR, "too many address in hostent (%d), ignoring others",
145 if (hent->h_addr_list[hostnum] == NULL) {
146 /* shouldn't happen */
147 syslog (LOG_ERR, "hent->h_addr_list[hostnum] == NULL! foo!");
151 #ifdef DO_CONNECT_DEBUG_SYSLOGS
152 dbgbuflen += snprintf (dbgbuf+dbgbuflen, 2047-dbgbuflen,
153 "[%d: %d.%d.%d.%d] ", sizeof (struct in_addr),
154 hent->h_addr_list[hostnum][0],
155 hent->h_addr_list[hostnum][1],
156 hent->h_addr_list[hostnum][2],
157 hent->h_addr_list[hostnum][3]);
160 memcpy ((void *) &(inaddrlist[hostnum]),
161 (void *) hent->h_addr_list[hostnum],
162 sizeof (struct in_addr));
165 #ifdef DO_CONNECT_DEBUG_SYSLOGS
166 syslog (LOG_DEBUG, "dbg: %d %s", hostnum, dbgbuf); dbgbuflen = 0;
171 #ifdef DO_CONNECT_DEBUG_SYSLOGS
172 for (dbgiter = 0; dbgiter < hostnum; dbgiter++) {
173 syslog (LOG_DEBUG, "dbg: host addr %d/%d = %lx at %lx", dbgiter, hostnum,
174 inaddrlist[dbgiter].s_addr, &(inaddrlist[dbgiter]));
178 hent = NULL; /* cannot use hent after this point, syslog() may overwrite it */
180 #ifdef DO_CONNECT_DEBUG_SYSLOGS
181 syslog (LOG_DEBUG, "dbg: socket");
184 if(-1 == (mysock = socket(PF_INET,SOCK_STREAM,0)))
186 origerr = errno; /* take a copy before syslog() */
187 syslog (LOG_ERR, "socket() to spamd failed: %m");
190 case EPROTONOSUPPORT:
205 #ifdef USE_TCP_NODELAY
206 /* TODO: should this be up above the connect()? */
207 value = 1; /* make this explicit! */
208 if(-1 == setsockopt(mysock,0,TCP_NODELAY,&value,sizeof(value)))
216 syslog (LOG_ERR, "setsockopt() to spamd failed: %m");
226 for (numloops=0; numloops < MAX_CONNECT_RETRIES; numloops++) {
228 #ifdef DO_CONNECT_DEBUG_SYSLOGS
229 syslog (LOG_DEBUG, "dbg: connect() to spamd %d", numloops);
232 if (argaddr != NULL) {
233 addr = (struct sockaddr_in *) argaddr; /* use the one provided */
235 #ifdef DO_CONNECT_DEBUG_SYSLOGS
236 syslog (LOG_DEBUG, "dbg: using argaddr");
240 /* cycle through the addrs in hent */
241 memset(&addrbuf, 0, sizeof(addrbuf));
242 addrbuf.sin_family=AF_INET;
243 addrbuf.sin_port=htons(hent_port);
245 if (sizeof(addrbuf.sin_addr) != sizeof(struct in_addr)) { /* shouldn't happen */
247 "foo! sizeof(sockaddr.sin_addr) != sizeof(struct in_addr)");
251 #ifdef DO_CONNECT_DEBUG_SYSLOGS
252 syslog (LOG_DEBUG, "dbg: cpy addr %d/%d at %lx",
253 numloops%hostnum, hostnum, &(inaddrlist[numloops % hostnum]));
256 memcpy (&addrbuf.sin_addr, &(inaddrlist[numloops % hostnum]),
257 sizeof(addrbuf.sin_addr));
260 #ifdef DO_CONNECT_DEBUG_SYSLOGS
261 syslog (LOG_DEBUG, "dbg: conn addr %d/%d = %lx",
262 numloops%hostnum, hostnum, addrbuf.sin_addr.s_addr);
267 #ifdef DO_CONNECT_DEBUG_SYSLOGS
268 syslog (LOG_DEBUG, "dbg: connect() to spamd at %s",
269 inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
271 status = connect(mysock,(const struct sockaddr *) addr, sizeof(*addr));
273 #ifdef DO_CONNECT_DEBUG_SYSLOGS
274 syslog (LOG_DEBUG, "dbg: connect() to spamd at %s done",
275 inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
280 origerr = errno; /* take a copy before syslog() */
281 syslog (LOG_ERR, "connect() to spamd at %s failed, retrying (%d/%d): %m",
282 inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
283 numloops+1, MAX_CONNECT_RETRIES);
284 sleep(CONNECT_RETRY_SLEEP);
292 /* failed, even with a few retries */
294 syslog (LOG_ERR, "connection attempt to spamd aborted after %d retries",
295 MAX_CONNECT_RETRIES);
311 return EX_UNAVAILABLE;
319 /* Aug 14, 2002 bj: Reworked things. Now we have message_read, message_write,
320 * message_dump, lookup_host, message_filter, and message_process, and a bunch
321 * of helper functions.
324 static void clear_message(struct message *m){
325 m->type=MESSAGE_NONE;
326 m->raw=NULL; m->raw_len=0;
327 m->pre=NULL; m->pre_len=0;
328 m->msg=NULL; m->msg_len=0;
329 m->post=NULL; m->post_len=0;
330 m->is_spam=EX_TOOBIG;
331 m->score=0.0; m->threshold=0.0;
332 m->out=NULL; m->out_len=0;
333 m->content_length=-1;
337 message_read_raw(int fd, struct message *m){
339 if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR;
340 m->raw_len=full_read(fd, (unsigned char *) m->raw, m->max_len+1, m->max_len+1);
342 free(m->raw); m->raw=NULL; m->raw_len=0;
345 m->type=MESSAGE_ERROR;
346 if(m->raw_len>m->max_len) return EX_TOOBIG;
349 m->msg_len=m->raw_len;
351 m->out_len=m->msg_len;
355 static int message_read_bsmtp(int fd, struct message *m){
360 if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR;
362 /* Find the DATA line */
363 m->raw_len=full_read(fd, (unsigned char *) m->raw, m->max_len+1, m->max_len+1);
365 free(m->raw); m->raw=NULL; m->raw_len=0;
368 m->type=MESSAGE_ERROR;
369 if(m->raw_len>m->max_len) return EX_TOOBIG;
371 for(i=0; i<m->raw_len-6; i++){
372 if((m->raw[i]=='\n') &&
373 (m->raw[i+1]=='D' || m->raw[i+1]=='d') &&
374 (m->raw[i+2]=='A' || m->raw[i+2]=='a') &&
375 (m->raw[i+3]=='T' || m->raw[i+3]=='t') &&
376 (m->raw[i+4]=='A' || m->raw[i+4]=='a') &&
377 ((m->raw[i+5]=='\r' && m->raw[i+6]=='\n') || m->raw[i+5]=='\n')){
380 if(m->raw[i-1]=='\r') i++;
383 m->msg_len=m->raw_len-i;
387 if(m->msg==NULL) return EX_DATAERR;
389 /* Find the end-of-DATA line */
391 for(i=j=0; i<m->msg_len; i++){
392 if(prev=='\n' && m->msg[i]=='.'){
393 /* Dot at the beginning of a line */
394 if((m->msg[i+1]=='\r' && m->msg[i+2]=='\n') || m->msg[i+1]=='\n'){
395 /* Lone dot! That's all, folks */
397 m->post_len=m->msg_len-i;
400 } else if(m->msg[i+1]=='.'){
401 /* Escaping dot, eliminate. */
404 } /* Else an ordinary dot, drop down to ordinary char handler */
407 m->msg[j++]=m->msg[i];
410 m->type=MESSAGE_BSMTP;
412 m->out_len=m->msg_len;
416 int message_read(int fd, int flags, struct message *m){
417 libspamc_timeout = 0;
419 switch(flags&SPAMC_MODE_MASK){
421 return message_read_raw(fd, m);
423 case SPAMC_BSMTP_MODE:
424 return message_read_bsmtp(fd, m);
427 syslog(LOG_ERR, "message_read: Unknown mode %d\n", flags&SPAMC_MODE_MASK);
432 long message_write(int fd, struct message *m){
438 /* if we're to output a message, m->is_spam will be EX_OUTPUTMESSAGE */
439 if(m->is_spam==EX_ISSPAM || m->is_spam==EX_NOTSPAM){
440 return full_write(fd, (unsigned char *) m->out, m->out_len);
443 if (m->is_spam != EX_OUTPUTMESSAGE && m->is_spam != EX_TOOBIG) {
445 "Cannot write this message, is_spam = %d!\n", m->is_spam);
451 syslog(LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!\n");
455 return full_write(fd, (unsigned char *) m->raw, m->raw_len);
458 return full_write(fd, (unsigned char *) m->out, m->out_len);
461 total=full_write(fd, (unsigned char *) m->pre, m->pre_len);
462 for(i=0; i<m->out_len; ){
463 jlimit = (off_t) (sizeof(buffer)/sizeof(*buffer)-4);
464 for(j=0; i < (off_t) m->out_len &&
467 if(i+1<m->out_len && m->out[i]=='\n' && m->out[i+1]=='.'){
468 if (j > jlimit - 4) {
469 break; /* avoid overflow */
471 buffer[j++]=m->out[i++];
472 buffer[j++]=m->out[i++];
475 buffer[j++]=m->out[i++];
478 total+=full_write(fd, (unsigned char *) buffer, j);
480 return total+full_write(fd, (unsigned char *) m->post, m->post_len);
483 syslog(LOG_ERR, "Unknown message type %d\n", m->type);
488 void message_dump(int in_fd, int out_fd, struct message *m){
492 if(m!=NULL && m->type!=MESSAGE_NONE) {
493 message_write(out_fd, m);
495 while((bytes=full_read(in_fd, (unsigned char *) buf, 8192, 8192))>0){
496 if (bytes!=full_write(out_fd, (unsigned char *) buf, bytes)) {
497 syslog(LOG_ERR, "oops! message_dump of %d returned different", bytes);
503 _spamc_read_full_line (struct message *m, int flags, SSL *ssl, int sock,
504 char *buf, int *lenp, int bufsiz)
510 /* Now, read from spamd */
511 for(len=0; len<bufsiz-1; len++) {
512 if(flags&SPAMC_USE_SSL) {
513 bytesread = ssl_timeout_read (ssl, buf+len, 1);
515 bytesread = fd_timeout_read (sock, buf+len, 1);
520 if (len > 0 && buf[len-1] == '\r') {
529 failureval = EX_IOERR; goto failure;
533 syslog(LOG_ERR, "spamd responded with line of %d bytes, dying", len);
534 failureval = EX_TOOBIG;
541 * May 7 2003 jm: using %f is bad where LC_NUMERIC is "," in the locale.
542 * work around using our own locale-independent float-parser code.
545 _locale_safe_string_to_float (char *buf, int siz)
552 buf[siz-1] = '\0'; /* ensure termination */
554 /* ok, let's illustrate using "100.033" as an example... */
557 if (*buf == '-') { is_neg = 1; }
559 ret = (float) (strtol (buf, &dot, 10));
560 if (dot == NULL) { return 0.0; }
561 if (dot != NULL && *dot != '.') { return ret; }
563 /* ex: ret == 100.0 */
566 postdot = (float) (strtol (cp, NULL, 10));
567 if (postdot == 0.0) { return ret; }
569 /* ex: postdot == 33.0, cp="033" */
571 /* now count the number of decimal places and figure out what power of 10 to use */
573 while (*cp != '\0') {
578 * cp="033", divider=1
579 * cp="33", divider=10
580 * cp="3", divider=100
581 * cp="", divider=1000
585 ret -= (postdot / ((float) divider));
587 ret += (postdot / ((float) divider));
589 /* ex: ret == 100.033, tada! ... hopefully */
595 _handle_spamd_header (struct message *m, int flags, char *buf, int len)
598 char s_str[20], t_str[20];
600 /* Feb 12 2003 jm: actually, I think sccanf is working fine here ;)
601 * let's stick with it for this parser.
602 * May 7 2003 jm: using %f is bad where LC_NUMERIC is "," in the locale.
603 * work around using our own locale-independent float-parser code.
605 if (sscanf(buf, "Spam: %5s ; %20s / %20s", is_spam, s_str, t_str) == 3)
607 m->score = _locale_safe_string_to_float (s_str, 20);
608 m->threshold = _locale_safe_string_to_float (t_str, 20);
610 /* Format is "Spam: x; y / x" */
611 m->is_spam=strcasecmp("true", is_spam) == 0 ? EX_ISSPAM: EX_NOTSPAM;
613 if(flags&SPAMC_CHECK_ONLY) {
614 m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE,
615 "%.1f/%.1f\n", m->score, m->threshold);
619 } else if(sscanf(buf, "Content-length: %d", &m->content_length) == 1) {
620 if (m->content_length < 0) {
621 syslog(LOG_ERR, "spamd responded with bad Content-length '%s'", buf);
627 syslog(LOG_ERR, "spamd responded with bad header '%s'", buf);
631 static int _message_filter(const struct sockaddr *addr,
632 const struct hostent *hent, int hent_port, char *username,
633 int flags, struct message *m)
636 int bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
647 if (flags&SPAMC_USE_SSL) {
649 SSLeay_add_ssl_algorithms();
650 meth = SSLv2_client_method();
651 SSL_load_error_strings();
652 ctx = SSL_CTX_new(meth);
654 (void) ssl; (void) meth; (void) ctx; /* avoid "unused" warnings */
655 syslog(LOG_ERR, "spamc not built with SSL support");
660 m->is_spam=EX_TOOBIG;
661 if((m->out=malloc(m->max_len+EXPANSION_ALLOWANCE+1))==NULL){
662 failureval = EX_OSERR; goto failure;
667 /* Build spamd protocol header */
668 if(flags & SPAMC_CHECK_ONLY)
669 len=snprintf(buf, bufsiz, "CHECK %s\r\n", PROTOCOL_VERSION);
670 else if(flags & SPAMC_REPORT_IFSPAM)
671 len=snprintf(buf, bufsiz, "REPORT_IFSPAM %s\r\n", PROTOCOL_VERSION);
672 else if(flags & SPAMC_REPORT)
673 len=snprintf(buf, bufsiz, "REPORT %s\r\n", PROTOCOL_VERSION);
674 else if(flags & SPAMC_SYMBOLS)
675 len=snprintf(buf, bufsiz, "SYMBOLS %s\r\n", PROTOCOL_VERSION);
677 len=snprintf(buf, bufsiz, "PROCESS %s\r\n", PROTOCOL_VERSION);
679 if(len<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
681 len+=i=snprintf(buf+len, bufsiz-len, "User: %s\r\n", username);
682 if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
684 len+=i=snprintf(buf+len, bufsiz-len, "Content-length: %d\r\n", m->msg_len);
685 if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
686 len+=i=snprintf(buf+len, bufsiz-len, "\r\n");
687 if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
689 libspamc_timeout = m->timeout;
691 if((i=try_to_connect(addr, (struct hostent *) hent,
692 hent_port, &sock)) != EX_OK)
694 free(m->out); m->out=m->msg; m->out_len=m->msg_len;
698 if(flags&SPAMC_USE_SSL) {
701 SSL_set_fd(ssl, sock);
707 if(flags&SPAMC_USE_SSL) {
709 SSL_write(ssl, buf, len);
710 SSL_write(ssl, m->msg, m->msg_len);
713 full_write(sock, (unsigned char *) buf, len);
714 full_write(sock, (unsigned char *) m->msg, m->msg_len);
715 shutdown(sock, SHUT_WR);
718 /* ok, now read and parse it. SPAMD/1.2 line first... */
719 failureval = _spamc_read_full_line (m, flags, ssl, sock, buf, &len, bufsiz);
720 if (failureval != EX_OK) { goto failure; }
722 if(sscanf(buf, "SPAMD/%s %d %*s", versbuf, &response)!=2) {
723 syslog(LOG_ERR, "spamd responded with bad string '%s'", buf);
724 failureval = EX_PROTOCOL; goto failure;
727 version = _locale_safe_string_to_float (versbuf, 20);
729 syslog(LOG_ERR, "spamd responded with bad version string '%s'", versbuf);
730 failureval = EX_PROTOCOL; goto failure;
735 m->is_spam = EX_TOOBIG;
737 failureval = _spamc_read_full_line (m, flags, ssl, sock, buf, &len, bufsiz);
738 if (failureval != EX_OK) { goto failure; }
740 if (len == 0 && buf[0] == '\0') {
741 break; /* end of headers */
744 if (_handle_spamd_header(m, flags, buf, len) < 0) {
745 failureval = EX_PROTOCOL; goto failure;
749 len = 0; /* overwrite those headers */
751 if (flags&SPAMC_CHECK_ONLY) {
752 close(sock); sock = -1;
753 if (m->is_spam == EX_TOOBIG) {
754 /* We should have gotten headers back... Damnit. */
755 failureval = EX_PROTOCOL; goto failure;
760 m->is_spam=EX_OUTPUTMESSAGE;
761 if (m->content_length < 0) {
762 /* should have got a length too. */
763 failureval = EX_PROTOCOL; goto failure;
766 if (flags&SPAMC_USE_SSL) {
767 len = ssl_timeout_read (ssl, m->out+m->out_len,
768 m->max_len+EXPANSION_ALLOWANCE+1-m->out_len);
770 len = full_read (sock, (unsigned char *) m->out+m->out_len,
771 m->max_len+EXPANSION_ALLOWANCE+1-m->out_len,
772 m->max_len+EXPANSION_ALLOWANCE+1-m->out_len);
776 if(len+m->out_len>m->max_len+EXPANSION_ALLOWANCE){
777 failureval = EX_TOOBIG; goto failure;
781 shutdown(sock, SHUT_RD);
782 close(sock); sock = -1;
784 libspamc_timeout = 0;
786 if(m->out_len!=m->content_length) {
787 syslog(LOG_ERR, "failed sanity check, %d bytes claimed, %d bytes seen",
788 m->content_length, m->out_len);
789 failureval = EX_PROTOCOL; goto failure;
795 free(m->out); m->out=m->msg; m->out_len=m->msg_len;
799 libspamc_timeout = 0;
801 if(flags&SPAMC_USE_SSL) {
810 static int _lookup_host(const char *hostname, struct hostent *out_hent)
812 struct hostent *hent = NULL;
815 /* no need to try using inet_addr(), gethostbyname() will do that */
817 if (NULL == (hent = gethostbyname(hostname))) {
818 origherr = h_errno; /* take a copy before syslog() */
819 syslog (LOG_ERR, "gethostbyname(%s) failed: h_errno=%d",
834 memcpy (out_hent, hent, sizeof(struct hostent));
839 int message_process(const char *hostname, int port, char *username, int max_size, int in_fd, int out_fd, const int flags){
846 ret=lookup_host_for_failover(hostname, &hent);
847 if(ret!=EX_OK) goto FAIL;
850 ret=message_read(in_fd, flags, &m);
851 if(ret!=EX_OK) goto FAIL;
852 ret=message_filter_with_failover(&hent, port, username, flags, &m);
853 if(ret!=EX_OK) goto FAIL;
854 if(message_write(out_fd, &m)<0) goto FAIL;
855 if(m.is_spam!=EX_TOOBIG) {
863 if(flags&SPAMC_CHECK_ONLY){
864 full_write(out_fd, (unsigned char *) "0/0\n", 4);
868 message_dump(in_fd, out_fd, &m);
874 void message_cleanup(struct message *m) {
875 if (m->out != NULL && m->out != m->raw) free(m->out);
876 if (m->raw != NULL) free(m->raw);
880 /* Aug 14, 2002 bj: Obsolete! */
881 int process_message(const char *hostname, int port, char *username, int max_size, int in_fd, int out_fd, const int my_check_only, const int my_safe_fallback){
884 flags=SPAMC_RAW_MODE;
885 if(my_check_only) flags|=SPAMC_CHECK_ONLY;
886 if(my_safe_fallback) flags|=SPAMC_SAFE_FALLBACK;
888 return message_process(hostname, port, username, max_size, in_fd, out_fd, flags);
891 /* public APIs, which call into the static code and enforce sockaddr-OR-hostent
894 int lookup_host(const char *hostname, int port, struct sockaddr *out_addr)
896 struct sockaddr_in *addr = (struct sockaddr_in *)out_addr;
900 memset(&out_addr, 0, sizeof(out_addr));
901 addr->sin_family=AF_INET;
902 addr->sin_port=htons(port);
903 ret = _lookup_host(hostname, &hent);
904 memcpy (&(addr->sin_addr), hent.h_addr, sizeof(addr->sin_addr));
908 int lookup_host_for_failover(const char *hostname, struct hostent *hent) {
909 return _lookup_host(hostname, hent);
912 int message_filter(const struct sockaddr *addr, char *username, int flags,
914 { return _message_filter (addr, NULL, 0, username, flags, m); }
916 int message_filter_with_failover (const struct hostent *hent, int port,
917 char *username, int flags, struct message *m)
918 { return _message_filter (NULL, hent, port, username, flags, m); }