OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / pop3proxy / ip-lib.c
1
2 /*
3
4     File: ip-lib.c
5  
6     Copyright (C) 1999,2004 by Wolfgang Zekoll <wzk@quietsche-entchen.de>
7
8     This source is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 1, or (at your option)
11     any later version.
12
13     This source is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include <signal.h>
29 #include <syslog.h>
30 #include <ctype.h>
31
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <netinet/in.h>
37 #include <netdb.h>
38 #include <errno.h>
39
40 #include "lib.h"
41 #include "ip-lib.h"
42 #include "pop3.h"
43
44
45
46 unsigned int get_interface_info(int pfd, peer_t *sock)
47 {
48         int     size;
49         struct sockaddr_in saddr;
50
51         size = sizeof(saddr);
52         if (getsockname(pfd, (struct sockaddr *) &saddr, &size) < 0)
53                 printerror(1, "-ERR", "can't get sockname, error= %s", strerror(errno));
54
55         copy_string(sock->ipnum, (char *) inet_ntoa(saddr.sin_addr), sizeof(sock->ipnum));
56         sock->port = ntohs(saddr.sin_port);
57         copy_string(sock->name, sock->ipnum, sizeof(sock->name));
58
59         return (sock->port);
60 }
61
62
63 static void alarm_handler()
64 {
65         return;
66 }
67
68         /*
69          * This version of openip() was copied+pasted from ftp.proxy -- 28OCT04wzk
70          */
71
72 int openip(char *host, unsigned int port, char *srcip, unsigned int srcport)
73 {
74         int     socketd;
75         struct sockaddr_in server;
76         struct hostent *hostp, *gethostbyname();
77
78         socketd = socket(AF_INET, SOCK_STREAM, 0);
79         if (socketd < 0)
80                 return (-1);
81   
82         if (srcip != NULL  &&  *srcip != 0) {
83                 struct sockaddr_in laddr;
84
85                 if (srcport != 0) {
86                         int     one;
87
88                         one = 1;
89                         setsockopt (socketd, SOL_SOCKET, SO_REUSEADDR, (int *) &one, sizeof(one));
90                         }
91  
92                 /*
93                  * Bind local socket to srcport and srcip
94                  */
95
96                 memset(&laddr, 0, sizeof(laddr));
97                 laddr.sin_family = AF_INET;
98                 laddr.sin_port   = htons(srcport);
99
100                 if (srcip == NULL  ||  *srcip == 0)
101                         srcip = "0.0.0.0";      /* Can't happen but who cares. */
102                 else {
103                         struct hostent *ifp;
104  
105                         ifp = gethostbyname(srcip);
106                         if (ifp == NULL)
107                                 printerror(1, "-ERR", "can't lookup %s", srcip);
108  
109                         memcpy(&laddr.sin_addr, ifp->h_addr, ifp->h_length);
110                         }
111  
112                 if (bind(socketd, (struct sockaddr *) &laddr, sizeof(laddr)))
113                         printerror(1, "-ERR", "can't bind to %s:%u", srcip, ntohs(laddr.sin_port));
114                 }
115
116
117         server.sin_family = AF_INET;
118         hostp = gethostbyname(host);
119         if (hostp == NULL)
120                 return (-1);
121   
122         memcpy(&server.sin_addr, hostp->h_addr, hostp->h_length);
123         server.sin_port = htons(port);
124
125         signal(SIGALRM, alarm_handler);
126         alarm(10);
127         if (connect(socketd, (struct sockaddr *) &server, sizeof(server)) < 0)
128                 return (-1);
129
130         alarm(0);
131         signal(SIGALRM, SIG_DFL);
132         
133         return (socketd);
134 }       
135
136 unsigned int getportnum(char *name)
137 {
138         unsigned int port;
139         struct servent *portdesc;
140         
141         if (isdigit(*name) != 0)
142                 port = atol(name);
143         else {
144                 portdesc = getservbyname(name, "tcp");
145                 if (portdesc == NULL)
146                         printerror(1, "-ERR", "service not found: %s", name);
147
148                 port = ntohs(portdesc->s_port);
149                 if (port == 0)
150                         printerror(1, "-ERR", "port error: %s", name);
151                 }
152         
153         return (port);
154 }
155
156 unsigned int get_port(char *server, unsigned int def_port)
157 {
158         unsigned int port;
159         char    *p;
160
161         if ((p = strchr(server, ':')) == NULL)
162                 return (def_port);
163
164         *p++ = 0;
165         port = getportnum(p);
166
167         return (port);
168 }
169
170 int bind_to_port(char *interface, unsigned int port)
171 {
172         struct sockaddr_in saddr;
173         int     sock;
174
175         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
176                 printerror(1, "-ERR", "can't create socket: %s", strerror(errno));
177         else {
178                 int     opt;
179
180                 opt = 1;
181                 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
182                 }
183
184
185         memset(&saddr, 0, sizeof(saddr));
186         saddr.sin_family = AF_INET;
187         saddr.sin_port   = htons(port);
188         
189         if (interface == NULL  ||  *interface == 0)
190                 interface = "0.0.0.0";
191         else {
192                 struct hostent *ifp;
193
194                 ifp = gethostbyname(interface);
195                 if (ifp == NULL)
196                         printerror(1, "-ERR", "can't lookup %s", interface);
197
198                 memcpy(&saddr.sin_addr, ifp->h_addr, ifp->h_length);
199                 }
200                 
201                 
202         if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)))
203                 printerror(1, "-ERR", "can't bind to %s:%u", interface, port);
204
205         if (listen(sock, 5) < 0)
206                 printerror(1, "-ERR", "listen error:  %s", strerror(errno));
207
208         return (sock);
209 }
210
211 int acceptloop(int sock)
212 {
213         int     connect, pid, len;
214         struct sockaddr_in client;
215
216         if (debug != 0)
217                 ;
218         else if ((pid = fork()) > 0)
219                 exit (1);
220
221         if (debug != 0)
222                 fprintf (stderr, "%u: entering daemon mode ...\n", getpid());
223
224         while (1) {
225                 len = sizeof(client);
226                 if ((connect = accept(sock, (struct sockaddr *) &client, &len)) < 0) {
227                         if (errno == EINTR  ||  errno == ECONNABORTED)
228                                 continue;
229
230                         fprintf (stderr, "%u: accept error: %s\n", getpid(), strerror(errno));
231                         continue;
232                         }
233
234                 if ((pid = fork()) < 0) {
235                         fprintf (stderr, "%u: can't fork process: %s\n", getpid(), strerror(errno));
236                         exit (1);
237                         }
238                 else if (pid == 0) {
239                         int optlen;
240                         struct linger linger;
241
242                         linger.l_onoff = 1;
243                         linger.l_linger = 2;
244                         optlen = sizeof(linger);
245                         if (setsockopt(connect, SOL_SOCKET, SO_LINGER, &linger, optlen) != 0)
246                                 fprintf (stderr, "%u: can't set linger\n", getpid());
247
248                         dup2(connect, 0);
249                         dup2(connect, 1);
250
251                         close (connect);
252                         close (sock);
253
254                         return (0);
255                         }
256
257                 close(connect);
258                 }
259
260         if (debug != 0)
261                 fprintf (stderr, "%u: terminating\n", getpid());
262
263         exit (0);
264 }
265
266
267 int getpeerinfo(int pfd, char *ipnum, int ipsize, char *name, int namesize, int interface)
268 {
269         int     rc, size;
270         struct sockaddr_in saddr;
271         struct in_addr *addr;
272         struct hostent *hostp = NULL;
273
274         *ipnum = 0;
275         size = sizeof(saddr);
276         if (interface == 0)
277                 rc = getpeername(pfd, (struct sockaddr *) &saddr, &size); 
278         else
279                 rc = getsockname(pfd, (struct sockaddr *) &saddr, &size);
280
281         if (rc < 0) {
282                 if (interface == 0)
283                         copy_string(ipnum, isatty(pfd) == 0? "127.0.0.2": "127.0.0.1", ipsize - 2);
284                 else
285                         copy_string(ipnum, "127.0.0.1", ipsize - 2);
286
287                 if (name != NULL)
288                         copy_string(name, "localhost", namesize);
289
290                 return (0);
291                 }               
292                 
293         copy_string(ipnum, (char *) inet_ntoa(saddr.sin_addr), ipsize);
294         if (name != NULL) {
295                 addr = &saddr.sin_addr,
296                 hostp = gethostbyaddr((char *) addr,
297                                 sizeof (saddr.sin_addr.s_addr), AF_INET);
298
299                 if (hostp == NULL)
300                         copy_string(name, ipnum, namesize - 2);
301                 else {
302                         copy_string(name, hostp->h_name, namesize - 2);
303                         strlwr(name);
304                         }
305                 }
306
307         return (0);
308 }
309