chiark / gitweb /
changelog: Document -t option
[chiark-utils.git] / cprogs / smtpallow.c
1 /*
2  * smtpallow.c - ld_preload for hacking with connect() !
3  *
4  * Copyright (C) 1994,1995 Ian Jackson <ian@davenant.greenend.org.uk>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 3,
9  * or (at your option) any later version.
10  *
11  * This is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this file; if not, consult the Free Software
18  * Foundation's website at www.fsf.org, or the GNU Project website at
19  * www.gnu.org.
20  */
21
22 #include <syscall.h>
23 #include <sys/socketcall.h>
24 #include <netinet/in.h>
25 #include <string.h>
26
27 _syscall2(long,socketcall,int,call,unsigned long *,args);
28
29 int real_connect(int sockfd, const struct sockaddr *saddr, int addrlen)
30 {
31         unsigned long args[3];
32
33         args[0] = sockfd;
34         args[1] = (unsigned long)saddr;
35         args[2] = addrlen;
36         return socketcall(SYS_CONNECT, args);
37 }
38
39 int connect(int fd, const struct sockaddr *them_any, int addrlen) {
40   struct sockaddr_in *them= (struct sockaddr_in*)them_any;
41   int r,l,i;
42   struct sockaddr_in us;
43   
44   if (addrlen == sizeof(us) &&
45       them->sin_family == AF_INET &&
46       them->sin_port == htons(25)) {
47     memset(&us,0,sizeof(us));
48     us.sin_port= 0;
49     us.sin_family= AF_INET;
50     us.sin_addr.s_addr= INADDR_ANY;
51     r= getsockname(fd,(struct sockaddr*)&us,&l);
52     if (r<0 && errno != EINVAL) return r;
53     if (!ntohs(us.sin_port)) {
54       for (i=1023; i>0; i--) {
55         us.sin_port= htons(i);
56         if (!bind(fd,(struct sockaddr*)&us,sizeof(us))) break;
57         if (errno != EADDRINUSE) return -1;
58       }
59       if (!i) return -1;
60     } else if (r<0) return r;
61   }
62   return real_connect(fd,them_any,addrlen);
63 }