ze-filter  (ze-filter-0.8.0-develop-180218)
ze-server.c
Go to the documentation of this file.
1 /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : janvier 2002
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 
25 #include <ze-sys.h>
26 
27 #include <ze-libjc.h>
28 
29 #define DEBUG_LEVEL 15
30 
31 #ifndef SZ_QUEUE
32 #define SZ_QUEUE 32
33 #endif
34 
35 static int tcp_server_listen(char *, char *, int, socklen_t *);
36 
37 static int local_server_listen(char *, socklen_t *);
38 
39 
40 /* ****************************************************************************
41  * *
42  * *
43  **************************************************************************** */
44 
45 static int
46 tcp_server_listen(ip, service, port, addrlen)
47  char *ip;
48  char *service;
49  int port;
50  socklen_t *addrlen;
51 {
52  struct sockaddr_in srv_sock;
53  int sd = -1;
54  int sopt;
55 
56  ASSERT(ip != NULL || service != NULL);
57 
58  {
59  struct addrinfo hints;
60  struct addrinfo *result, *rp;
61  int s;
62 
63  char iport[32], *sport;
64 
65  snprintf(iport, sizeof (iport), "%d", port);
66  sport = (service != NULL ? service : iport);
67 
68  ZE_MessageInfo(11, "tcp_server_listen : %s %s %d",
69  STRNULL(ip, "IP???"), STRNULL(service, "SERVICE?"), port);
70 
71  memset(&hints, 0, sizeof (struct addrinfo));
72  hints.ai_family = AF_UNSPEC;
73  hints.ai_socktype = SOCK_STREAM;
74  hints.ai_flags = AI_PASSIVE;
75  hints.ai_protocol = 0;
76  hints.ai_canonname = NULL;
77  hints.ai_addr = NULL;
78  hints.ai_next = NULL;
79 
80  s = getaddrinfo(ip, sport, &hints, &result);
81  if (s != 0)
82  {
83  ZE_LogSysError("getaddrinfo: %s", gai_strerror(s));
84  exit(EXIT_FAILURE);
85  }
86 
87  for (rp = result; rp != NULL; rp = rp->ai_next)
88  {
89  sd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
90  if (sd == -1)
91  continue;
92 
93  sopt = 1;
94  /* Tell the system to allow local addresses to be reused. */
95  if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *) &sopt,
96  sizeof (sopt)) < 0)
97  {
98  ZE_LogSysError("Error setsockopt(SO_REUSEADDR)");
99  (void) close(sd);
100  return -1;
101  }
102 
103  if (bind(sd, rp->ai_addr, rp->ai_addrlen) == 0)
104  break;
105 
106  close(sd);
107  }
108 
109  if (rp == NULL)
110  { /* No address succeeded */
111  ZE_LogMsgError(0, "Could not bind");
112  exit(EXIT_FAILURE);
113  }
114 
115  freeaddrinfo(result); /* No longer needed */
116  }
117 
118  if (listen(sd, SZ_QUEUE) < 0)
119  {
120  ZE_LogSysError("Error creating socket listening queue");
121  (void) close(sd);
122  return -1;
123  }
124 
125  if (addrlen != NULL)
126  *addrlen = sizeof (srv_sock);
127 
128  return sd;
129 }
130 
131 /* ****************************************************************************
132  * *
133  * *
134  **************************************************************************** */
135 static int
136 local_server_listen(sname, addrlen)
137  char *sname;
138  socklen_t *addrlen;
139 {
140  struct sockaddr_un srv_sock;
141  int sd = -1;
142 
143  if ((sname == NULL) || (strlen(sname) == 0))
144  return sd;
145 
146  unlink(sname);
147 
148  memset(&srv_sock, 0, sizeof (srv_sock));
149  srv_sock.sun_family = AF_UNIX;
150 
151  strlcpy(srv_sock.sun_path, sname, sizeof (srv_sock.sun_path));
152 
153  /* Let's create reception socket... */
154  if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
155  {
156  ZE_LogSysError("Error creating socket");
157  return -1;
158  }
159 
160  if (bind(sd, (struct sockaddr *) &srv_sock, sizeof (srv_sock)) < 0)
161  {
162  ZE_LogSysError("Error binding socket");
163  (void) close(sd);
164  return -1;
165  }
166 
167  if (listen(sd, SZ_QUEUE) < 0)
168  {
169  ZE_LogSysError("Error creating socket listening queue");
170  (void) close(sd);
171  return -1;
172  }
173 
174  if (addrlen != NULL)
175  *addrlen = sizeof (srv_sock);
176 
177  return sd;
178 }
179 
180 /* ****************************************************************************
181  * *
182  * *
183  * *
184  * *
185  **************************************************************************** */
186 static int
187 inet_server_listen(node, service, socktype, server)
188  char *node;
189  char *service;
190  int socktype;
191  server_T *server;
192 {
193  int sd = -1;
194  struct addrinfo hints;
195  struct addrinfo *addrinfo, *rp;
196  int s;
197 
198  ASSERT(node != NULL || service != NULL);
199 
200  if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
201  socktype = SOCK_STREAM;
202 
203  ZE_MessageInfo(12, "inet_server_listen : %s %s/%s",
204  STRNULL(node, "NODE???"), STRNULL(service, "SERVICE???"),
205  socktype == SOCK_STREAM ? "tcp" : "udp");
206 
207  memset(&hints, 0, sizeof (struct addrinfo));
208  hints.ai_family = AF_UNSPEC;
209  hints.ai_socktype = socktype;
210  hints.ai_flags = AI_PASSIVE;
211  hints.ai_protocol = 0;
212  hints.ai_canonname = NULL;
213  hints.ai_addr = NULL;
214  hints.ai_next = NULL;
215 
216  s = getaddrinfo(node, service, &hints, &addrinfo);
217  if (s != 0)
218  {
219  ZE_LogSysError("getaddrinfo: %s", gai_strerror(s));
220  exit(EXIT_FAILURE);
221  }
222 
223  for (rp = addrinfo; rp != NULL; rp = rp->ai_next)
224  {
225  int sopt;
226 
227  sd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
228  if (sd == -1)
229  continue;
230 
231  sopt = 1;
232  if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *) &sopt,
233  sizeof (sopt)) < 0)
234  {
235  ZE_LogSysError("Error setsockopt(SO_REUSEADDR)");
236  close(sd);
237  sd = -1;
238  continue;
239  }
240 
241  if (bind(sd, rp->ai_addr, rp->ai_addrlen) != 0)
242  {
243  ZE_LogSysError("Bind error");
244  close(sd);
245  sd = -1;
246  continue;
247  }
248 
249  if (socktype == SOCK_STREAM)
250  {
251  if (listen(sd, SZ_QUEUE) < 0)
252  {
253  ZE_LogSysError("Error creating listening socket");
254  close(sd);
255  sd = -1;
256  continue;
257  }
258  }
259 
260  if (server != NULL)
261  {
262  server->socklen = rp->ai_addrlen;
263  server->family = rp->ai_family;
264  server->protocol = rp->ai_protocol;
265  server->socktype = rp->ai_socktype;
266  server->sd = sd;
267  }
268  break;
269  }
270 
271  if (sd < 0)
272  {
273  /* XXXX not a good message - correct it */
274  ZE_LogMsgError(0, "Unable to create a listening socket");
275  if (server != NULL)
276  memset(server, 0, sizeof (server));
277  }
278 
279  freeaddrinfo(addrinfo);
280 
281 fin:
282  return sd;
283 }
284 
285 /* ****************************************************************************
286  * *
287  * *
288  **************************************************************************** */
289 #define STRPREFIX(s,pfx) STRNCASEEQUAL((s),(pfx),strlen(pfx))
290 
291 static char *
292 tcp_prefix(spec)
293  char *spec;
294 {
295  if (STRPREFIX(spec, "inet:"))
296  return "inet:";
297  if (STRPREFIX(spec, "tcp:"))
298  return "tcp:";
299  if (STRPREFIX(spec, "stream:"))
300  return "stream:";
301 
302  return NULL;
303 }
304 
305 static char *
306 udp_prefix(spec)
307  char *spec;
308 {
309  if (STRPREFIX(spec, "udp:"))
310  return "udp:";
311  if (STRPREFIX(spec, "dgram:"))
312  return "dgram:";
313 
314  return NULL;
315 }
316 
317 static char *
318 unix_prefix(spec)
319  char *spec;
320 {
321  if (STRPREFIX(spec, "unix:"))
322  return "unix:";
323  if (STRPREFIX(spec, "local:"))
324  return "local:";
325 
326  return NULL;
327 }
328 
329 /* ****************************************************************************
330  * *
331  * *
332  **************************************************************************** */
333 int
334 server_listen(spec, server)
335  char *spec;
336  server_T *server;
337 {
338  char *p, *s;
339 
340  if ((spec == NULL) || (strlen(spec) == 0))
341  return FALSE;
342 
343  ZE_MessageInfo(12, " CONTROL SOCKET %s", spec);
344 
345  if ((s = tcp_prefix(spec)) != NULL)
346  {
347  int fd = -1;
348  char sport[32], shost[128];
349  int argc;
350  char *argv[4];
351  char *ts = NULL;
352 
353  p = spec + strlen(s);
354 
355  memset(sport, 0, sizeof (sport));
356  memset(shost, 0, sizeof (shost));
357 
358  if ((ts = strdup(p)) == NULL)
359  {
360  ZE_LogSysError("strdup error");
361  goto fin;
362  }
363  argc = zeStr2Tokens(ts, 4, argv, "@");
364  if (argc == 0)
365  goto fin;
366 
367  strlcpy(sport, argv[0], sizeof (sport));
368  if (argc > 1)
369  strlcpy(shost, argv[1], sizeof (shost));
370  else
371  strlcpy(shost, "127.0.0.1", sizeof (shost));
372 
373  FREE(ts);
374 
375  ZE_MessageInfo(10, "Launching inet server on port [%s/tcp] of [%s]", sport,
376  shost);
377  fd = inet_server_listen(shost, sport, SOCK_STREAM, server);
378 
379  return fd;
380  }
381 
382  if ((s = udp_prefix(spec)) != NULL)
383  {
384  int fd = -1;
385  char sport[32], shost[128];
386  int argc;
387  char *argv[4];
388  char *ts = NULL;
389 
390  p = spec + strlen(s);
391 
392  memset(sport, 0, sizeof (sport));
393  memset(shost, 0, sizeof (shost));
394 
395  if ((ts = strdup(p)) == NULL)
396  {
397  ZE_LogSysError("strdup error");
398  goto fin;
399  }
400  argc = zeStr2Tokens(ts, 4, argv, "@");
401  if (argc == 0)
402  {
403  FREE(ts);
404  goto fin;
405  }
406 
407  strlcpy(sport, argv[0], sizeof (sport));
408  if (argc > 1)
409  strlcpy(shost, argv[1], sizeof (shost));
410  else
411  strlcpy(shost, "127.0.0.1", sizeof (shost));
412 
413  FREE(ts);
414 
415  ZE_MessageInfo(10, "Launching inet server on port [%s/udp] of [%s]", sport,
416  shost);
417  fd = inet_server_listen(shost, sport, SOCK_DGRAM, server);
418 
419  return fd;
420  }
421 
422 
423  if ((s = unix_prefix(spec)) != NULL)
424  {
425  int fd;
426  socklen_t addrlen;
427 
428  p = spec + strlen(s);
429 
430  if (*p != '/')
431  goto fin;
432 
433  ZE_MessageInfo(10, "Launching local server on %s", p);
434  fd = local_server_listen(p, &addrlen);
435  if (fd >= 0 && server != NULL)
436  {
437  server->family = AF_UNIX;
438  server->socklen = addrlen;
439  server->sd = fd;
440  }
441  return fd;
442  }
443 
444 fin:
445  return -1;
446 }
447 
int socklen_t
Definition: ze-sys.h:534
#define ASSERT(a)
Definition: macros.h:27
#define FREE(x)
Definition: macros.h:37
#define STRPREFIX(s, pfx)
Definition: ze-server.c:289
#define STRNULL(x, r)
Definition: macros.h:81
int server_listen(char *spec, server_T *server)
Definition: ze-server.c:334
#define FALSE
Definition: macros.h:160
#define strlcpy
Definition: zeString.h:32
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
int zeStr2Tokens(char *, int, char **, char *)
Definition: zeStrings.c:610
#define SZ_QUEUE
Definition: ze-server.c:32
socklen_t socklen
Definition: ze-server.h:33
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
int sd
Definition: ze-server.h:34
int family
Definition: ze-server.h:30
int socktype
Definition: ze-server.h:32
int protocol
Definition: ze-server.h:31