ucspi-tcp6 1.13.04
ucspi-tcp6
Loading...
Searching...
No Matches
tcpserver.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <unistd.h>
3#include <sys/param.h>
4#include <netdb.h>
5#include "uint_t.h"
6#include "str.h"
7#include "byte.h"
8#include "fmt.h"
9#include "scan.h"
10#include "ip.h"
11#include "fd.h"
12#include "exit.h"
13#include "env.h"
14#include "prot.h"
15#include "open.h"
16#include "wait.h"
17#include "genalloc.h"
18#include "stralloc.h"
19#include "alloc.h"
20#include "buffer.h"
21#include "logmsg.h"
22#include "getoptb.h"
23#include "pathexec.h"
24#include "socket_if.h"
25#include "ndelay.h"
26#include "remoteinfo.h"
27#include "rules.h"
28#include "sig.h"
29#include "dnsresolv.h"
30
31#define WHO "tcpserver"
32
33int verbosity = 1;
35int flagdelay = 1;
36char *banner = "";
40unsigned long timeout = 26;
41uint32 netif = 0;
43
44static stralloc tcpremoteinfo;
45
46uint16 localport;
47char localportstr[FMT_ULONG];
48char localip[16];
49char localipstr[IP6_FMT];
50static stralloc localhostsa;
51char *localhost = 0;
52const char *thishost = "0.0.0.0";
53
55char remoteportstr[FMT_ULONG];
56char remoteip[16];
57char remoteipstr[IP6_FMT];
58static stralloc remotehostsa;
59char *remotehost = 0;
60
61static char strnum[FMT_ULONG];
62static char strnum2[FMT_ULONG];
63static char strnum3[FMT_ULONG];
64
65static stralloc tmp;
66static stralloc fqdn;
67static stralloc addresses;
68
69unsigned long limit = 40;
70unsigned long numchildren = 0;
71unsigned long ipchildren = 0;
72unsigned long maxconip = 40;
73
74char bspace[16];
75buffer bo;
76
77void drop_nomem(void)
78{
79 logmsg(WHO,111,FATAL,"out of memory");
80}
81
82/* ---------------------------- per ip limit */
83
84struct child {
85 char ipaddr[16];
86 uint32 num;
87};
88
89GEN_ALLOC_typedef(child_alloc,struct child,c,len,a)
90GEN_ALLOC_readyplus(child_alloc,struct child,c,len,a,i,n,x,24,child_readyplus)
91GEN_ALLOC_append(child_alloc,struct child,c,len,a,i,n,x,24,child_readyplus,child_append)
92
93child_alloc children = {0};
94
95void ipchild_append(char ip[16],unsigned long n)
96{
97 struct child *ipchild = 0;
98
99 for (unsigned long i = 0; i <= n; ++i) {
100 ipchild = &children.c[i];
101 if (byte_equal(ipchild->ipaddr,16,ip)) {
102 ++ipchild->num;
103 break;
104 } else {
105 byte_copy(ipchild->ipaddr,16,ip);
106 ++ipchild->num;
107 break;
108 }
109 }
110}
111
112void ipchild_clear(char ip[16])
113{
114 struct child *ipchild = 0;
115
116 for (unsigned long i = 0; i <= children.len; ++i) {
117 ipchild = &children.c[i];
118 if (byte_equal(ipchild->ipaddr,16,ip)) {
119 if (ipchild->num) --ipchild->num;
120 break;
121 }
122 }
123}
124
125int ipchild_limit(char ip[16],unsigned long n)
126{
127
128 for (unsigned long i = 0; i <= n; ++i)
129 if (byte_equal(children.c[i].ipaddr,16,ip))
130 return children.c[i].num;
131
132 return 0;
133}
134
135/* ---------------------------- child */
136
137int flagdeny = 0;
138int flagallow = 0;
140char *fnrules = 0;
141char *fniprules = 0;
142
143void cats(char *s)
144{
145 if (!stralloc_cats(&tmp,s)) drop_nomem();
146}
147void append(char *ch)
148{
149 if (!stralloc_append(&tmp,ch)) drop_nomem();
150}
151void safecats(char *s)
152{
153 char ch;
154 int i;
155
156 for (i = 0; i < 100; ++i) {
157 ch = s[i];
158 if (!ch) return;
159 if (ch < 33) ch = '?';
160 if (ch > 126) ch = '?';
161 if (ch == '%') ch = '?'; /* logger stupidity */
162 append(&ch);
163 }
164 cats("...");
165}
166void env(const char *s,const char *t)
167{
168 if (!pathexec_env(s,t)) drop_nomem();
169}
170void drop_rules(const char *fnbase)
171{
172 logmsg(WHO,110,DROP,B("unable to read: ",fnbase));
173}
174
175void found(char *data,unsigned int datalen)
176{
177 unsigned int next0;
178 unsigned int split;
179
180 flagallow = 1; // used for IP match only
181
182 while ((next0 = byte_chr(data,datalen,0)) < datalen) {
183 switch(data[0]) {
184 case 'D':
185 flagdeny = 1; flagallow = 0;
186 break;
187 case '+':
188 flagallow = 2; // qualified match
189 split = str_chr(data + 1,'=');
190 if (data[1 + split] == '=') {
191 data[1 + split] = 0;
192 env(data + 1,data + 1 + split + 1);
193 if (!str_diff(data + 1,"MAXCONIP")) {
194 scan_ulong(data + 1 + split + 1,&maxconip);
195 if (limit && maxconip > limit) maxconip = limit;
196 if (ipchildren >= maxconip) { flagdeny = 2; }
197 }
198 }
199 break;
200 }
201 ++next0;
202 data += next0; datalen -= next0;
203 }
204}
205
206void doit(int t)
207{
208 int j;
209
210 if (socket_local(t,localip,&localport,&netif) == -1)
211 logmsg(WHO,111,FATAL,"unable to get local address");
212 if (flagkillopts)
213 socket_ipoptionskill(t);
214 if (!flagdelay)
215 socket_tcpnodelay(t);
216
217 if (ip6_isv4mapped(remoteip)) {
218 remoteipstr[ip4_fmt(remoteipstr,remoteip + 12)] = 0;
219 localipstr[ip4_fmt(localipstr,localip + 12)] = 0;
220 } else {
221 remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;
222 localipstr[ip6_fmt(localipstr,localip)] = 0;
223 }
224
225 if (verbosity >= 2) {
226 strnum[fmt_ulong(strnum,getpid())] = 0;
227 log_who(WHO,B("pid ",strnum," from ",remoteipstr));
228 }
229
230 if (*banner) {
231 buffer_init(&bo,buffer_unixwrite,t,bspace,sizeof(bspace));
232 if (buffer_putsflush(&bo,banner) == -1)
233 logmsg(WHO,111,FATAL,"unable to print banner");
234 }
235
236 if (!localhost)
237 if (dns_name(&localhostsa,localip) >= 0)
238 if (localhostsa.len) {
239 if (!stralloc_0(&localhostsa)) drop_nomem();
240 localhost = localhostsa.s;
241 }
242
243 remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0;
244
245/* Early evaluation of IP rules (only) */
246
247 if (fniprules) {
248 int fdrules;
249 fdrules = open_read(fniprules);
250 if (fdrules == -1) {
251 if (errno != ENOENT) drop_rules(fniprules);
253 } else {
254 if (rules(found,fdrules,remoteipstr,0,0) == -1)
256 close(fdrules);
257 }
258 }
259
260 if (flagdeny) goto FINISH;
261 if (flagallow) fnrules = 0;
262
263 if (flagremotehost)
264 if (dns_name(&remotehostsa,remoteip) >= 0)
265 if (remotehostsa.len) {
266 if (flagparanoid) {
267 if (dns_ip6(&tmp,&remotehostsa) >= 0)
268 for (j = 0; j + 16 <= tmp.len; j += 16)
269 if (byte_equal(remoteip,16,tmp.s + j)) {
270 flagparanoid = 0;
271 break;
272 }
273 if (dns_ip4(&tmp,&remotehostsa) >= 0)
274 for (j = 0; j + 4 <= tmp.len; j += 4)
275 if (byte_equal(remoteip + 12,4,tmp.s + j)) {
276 flagparanoid = 0;
277 break;
278 }
279 }
280 if (!flagparanoid) {
281 if (!stralloc_0(&remotehostsa)) drop_nomem();
282 remotehost = remotehostsa.s;
283 }
284 }
285
286 if (flagremoteinfo) {
287 if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1)
288 flagremoteinfo = 0;
289 if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
290 }
291
292 if (fnrules) {
293 int fdrules;
294 fdrules = open_read(fnrules);
295 if (fdrules == -1) {
296 if (errno != ENOENT) drop_rules(fnrules);
298 }
299 else {
300 if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(fnrules);
301 close(fdrules);
302 }
303 }
304
305 FINISH:
306 if (verbosity >= 2) {
307 strnum[fmt_ulong(strnum,getpid())] = 0;
308 strnum2[fmt_ulong(strnum2,maxconip)] = 0;
309 if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem();
310 safecats(flagdeny ? "deny" : "ok");
311 cats(" "); safecats(strnum);
312 cats(" "); if (localhost) safecats(localhost);
313 cats(":"); safecats(localipstr);
317 cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s);
319 if (flagdeny == 2) { cats(" ip connection limit:"); cats(strnum2); cats(" exceeded"); }
320 cats("\n");
321 buffer_putflush(buffer_2,tmp.s,tmp.len);
322 }
323
324 if (flagdeny) _exit(100);
325
326 /* Set up environment late */
327
328 env("PROTO",ip6_isv4mapped(remoteip)? "TCP":"TCP6");
329 env("TCPLOCALIP",localipstr);
330 env("TCPLOCALPORT",localportstr);
331 env("TCPLOCALHOST",localhost);
332 env("TCPREMOTEIP",remoteipstr);
333 env("TCPREMOTEPORT",remoteportstr);
334 env("TCPREMOTEHOST",remotehost);
335 if (!ip6_isv4mapped(remoteip)) {
336 env("TCP6LOCALIP",localipstr);
337 env("TCP6LOCALHOST",localhost);
338 env("TCP6LOCALPORT",localportstr);
339 if (netif) env("TCP6INTERFACE",socket_getifname(netif));
340 env("TCP6REMOTEIP",remoteipstr);
341 env("TCP6REMOTEPORT",remoteportstr);
342 env("TCP6REMOTEHOST",remotehost);
343 }
344 env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
345
346}
347
348
349/* ---------------------------- parent */
350
351void usage(void)
352{
353 logmsg(WHO,100,USAGE,"tcpserver \
354[ -46UxXpPhHrRoOdDqQv ] \
355[ -c limit ] \
356[ -x rules.cdb ] \
357[ -B banner ] \
358[ -g gid ] \
359[ -u uid ] \
360[ -b backlog ] \
361[ -l localname ] \
362[ -t timeout ] \
363[ -I interface ] \
364host port program");
365}
366
367int flag1 = 0;
368unsigned long backlog = 20;
369unsigned long uid = 0;
370unsigned long gid = 0;
371
372void printstatus(void)
373{
374 if (verbosity < 2) return;
375 strnum[fmt_ulong(strnum,numchildren)] = 0;
376 strnum2[fmt_ulong(strnum2,limit)] = 0;
377 strnum3[fmt_ulong(strnum3,maxconip)] = 0;
378 log_who(WHO,B("status: ",strnum,"/",strnum2,"/",strnum3));
379}
380
381static void sigterm(int dummy)
382{
383 _exit(0);
384}
385
386static void sigchld(int dummy)
387{
388 int wstat;
389 int pid;
390
391 while ((pid = wait_nohang(&wstat)) > 0) {
392 if (verbosity >= 2) {
393 strnum[fmt_ulong(strnum,pid)] = 0;
394 strnum2[fmt_ulong(strnum2,wstat)] = 0;
395 log_who(WHO,B("end ",strnum," status ",strnum2));
396 }
398 if (numchildren) --numchildren;
399 printstatus();
400 }
401}
402
403int main(int argc,char * const *argv)
404{
405 const char *hostname;
406 int opt;
407 struct servent *se;
408 char *x;
409 unsigned long u;
410 int j;
411 int s;
412 int t;
413 int ipflag = 0;
414
415 while ((opt = getoptb(argc,argv,"146dDvqQhHrRUXx:y:t:u:g:l:b:B:c:I:pPoO")) != opteof) {
416 switch(opt) {
417 case '1': flag1 = 1; break;
418 case '4': ipflag = 1; break;
419 case '6': ipflag = 2; break;
420 case 'd': flagdelay = 1; break;
421 case 'D': flagdelay = 0; break;
422 case 'v': verbosity = 2; break;
423 case 'q': verbosity = 0; break;
424 case 'Q': verbosity = 1; break;
425 case 'h': flagremotehost = 1; break;
426 case 'H': flagremotehost = 0; break;
427 case 'r': flagremoteinfo = 1; break;
428 case 'R': flagremoteinfo = 0; break;
429 case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid);
430 x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
431 case 'x': fnrules = optarg; break;
432 case 'X': flagallownorules = 1; break;
433 case 'y': fniprules = optarg; break;
434 case 't': scan_ulong(optarg,&timeout); break;
435 case 'u': scan_ulong(optarg,&uid); break;
436 case 'g': scan_ulong(optarg,&gid); break;
437 case 'l': localhost = optarg; break;
438 case 'b': scan_ulong(optarg,&backlog); break;
439 case 'B': banner = optarg; break;
440 case 'c': scan_ulong(optarg,&limit); maxconip = limit; break;
441 case 'I': netif = socket_getifidx(optarg); break;
442 case 'p': flagparanoid = 1; break;
443 case 'P': flagparanoid = 0; break;
444 case 'o': flagkillopts = 0; break;
445 case 'O': flagkillopts = 1; break;
446 default: usage();
447 }
448 }
449 argc -= optind;
450 argv += optind;
451
452 if (!verbosity)
453 buffer_2->fd = -1;
454
455 hostname = *argv++;
456 if (!hostname || str_equal((char *)hostname,"")) usage();
457 if (str_equal((char *)hostname,"0")) hostname = thishost;
458 else if (str_equal((char *)hostname,":0")) {
459 ipflag = 2;
460 flagdualstack = 1;
461 hostname = "::";
462 }
463
464 x = *argv++;
465 if (!x) usage();
466 if (!x[scan_ulong(x,&u)])
467 localport = u;
468 else {
469 se = getservbyname(x,"tcp");
470 if (!se)
471 logmsg(WHO,111,FATAL,B("unable to figure out port number for: ",x));
472 uint16_unpack_big((char*)&se->s_port,&localport);
473 }
474
475 if (!*argv) usage();
476
477 if ((x = env_get("MAXCONIP"))) { scan_ulong(x,&u); maxconip = u; }
478 if (!child_readyplus(&children,limit)) drop_nomem();
479
480 sig_block(sig_child);
481 sig_catch(sig_child,sigchld);
482 sig_catch(sig_term,sigterm);
483 sig_ignore(sig_pipe);
484
485 /* IP address only */
486
487 if (ip4_scan(hostname,localip)) {
488 if (!stralloc_copyb(&addresses,(char *)V4mappedprefix,12)) drop_nomem();
489 if (!stralloc_catb(&addresses,localip,4)) drop_nomem();
490 byte_copy(localip,16,addresses.s);
491 } else if (ip6_scan(hostname,localip)) {
492 if (!stralloc_copyb(&addresses,localip,16)) drop_nomem();
493 byte_copy(localip,16,addresses.s);
494 }
495
496 /* Asynchronous DNS IPv4/IPv6 Name qualification */
497
498 if (!addresses.len) {
499 if (!stralloc_copys(&tmp,hostname)) drop_nomem();
500 if (dns_ip_qualify(&addresses,&fqdn,&tmp) < 0)
501 logmsg(WHO,111,FATAL,B("temporarily unable to figure out IP address for: ",(char *)hostname));
502
503 byte_copy(localip,16,addresses.s);
504
505 for (j = 0; j < addresses.len; j += 16) { // Select best matching IP address
506 if (ipflag == 1 && !ip6_isv4mapped(addresses.s + j)) continue;
507 if (ipflag == 2 && ip6_isv4mapped(addresses.s + j)) continue;
508 byte_copy(localip,16,addresses.s + j);
509 }
510
511 }
512 if (addresses.len < 16)
513 logmsg(WHO,111,FATAL,B("no IP address for: ",(char *)hostname));
514
515 if (ip6_isv4mapped(localip))
516 s = socket_tcp4();
517 else
518 s = socket_tcp6();
519 if (s == -1)
520 logmsg(WHO,111,FATAL,"unable to create socket");
521 if (flagdualstack)
522 socket_dualstack(s);
523 if (socket_bind_reuse(s,localip,localport,netif) == -1)
524 logmsg(WHO,111,FATAL,"unable to bind");
525 if (socket_local(s,localip,&localport,&netif) == -1)
526 logmsg(WHO,111,FATAL,"unable to get local address");
527 if (socket_listen(s,backlog) == -1)
528 logmsg(WHO,111,FATAL,"unable to listen");
529 ndelay_off(s);
530
531 /* Swap user and permissions */
532
533 if (gid) if (prot_gid(gid) == -1)
534 logmsg(WHO,111,FATAL,"unable to set gid");
535 if (uid) if (prot_uid(uid) == -1)
536 logmsg(WHO,111,FATAL,"unable to set uid");
537
538 if (ip6_isv4mapped(localip))
539 localipstr[ip4_fmt(localipstr,localip + 12)] = 0;
540 else
541 localipstr[ip6_fmt(localipstr,localip)] = 0;
542 localportstr[fmt_ulong(localportstr,localport)] = 0;
543
544 /* Initial setup */
545
546 if (flag1) {
547 buffer_init(&bo,buffer_unixwrite,1,bspace,sizeof(bspace));
548 buffer_puts(&bo,localipstr);
549 buffer_puts(&bo," : ");
550 buffer_puts(&bo,localportstr);
551 buffer_puts(&bo," [");
552 strnum[fmt_ulong(strnum,limit)] = 0;
553 buffer_puts(&bo,strnum);
554 buffer_puts(&bo,"/");
555 strnum[fmt_ulong(strnum,maxconip)] = 0;
556 buffer_puts(&bo,strnum);
557 buffer_puts(&bo,"]");
558 buffer_puts(&bo,"\n");
559 buffer_flush(&bo);
560 }
561
562 close(0);
563 close(1);
564 printstatus();
565
566 for (;;) {
567 while (numchildren >= limit) sig_pause();
568 strnum[fmt_ulong(x,numchildren)] = 0;
569
570 sig_unblock(sig_child);
571 t = socket_accept(s,remoteip,&remoteport,&netif);
572 sig_block(sig_child);
573 if (t == -1) continue;
574
575 if (maxconip) {
577 if (ipchildren >= maxconip) {
578 if (ip6_isv4mapped(remoteip))
579 remoteipstr[ip4_fmt(remoteipstr,remoteip + 12)] = 0;
580 else
581 remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;
582
583 strnum[fmt_ulong(strnum,maxconip)] = 0;
584 logmsg(WHO,100,WARN,B("ip connection limit of ",strnum," exceeded for: ",remoteipstr));
585 close(t);
586 continue;
587 }
588 ipchild_append(remoteip,numchildren); // needs to happen in parent
589 }
590 ++numchildren;
591 printstatus();
592
593 switch(fork()) {
594 case 0:
595 close(s);
596 doit(t);
597 if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1))
598 logmsg(WHO,111,FATAL,"unable to set up descriptors");
599 sig_uncatch(sig_child);
600 sig_unblock(sig_child);
601 sig_uncatch(sig_term);
602 sig_uncatch(sig_pipe);
603 pathexec(argv);
604 logmsg(WHO,111,FATAL,B("unable to run: ",*argv));
605 case -1:
607 logmsg(WHO,111,FATAL,"unable to fork");
608 }
609 close(t);
610 }
611}
char bspace[BUFFER_SMALL]
Definition auto-str.c:4
int fork()
int close(int)
unsigned long timeout
Definition rblsmtpd.c:94
buffer bo
Definition mconnect-io.c:13
void drop_nomem(void)
Definition tcpserver.c:77
unsigned long ipchildren
Definition tcpserver.c:71
void ipchild_append(char ip[16], unsigned long n)
Definition tcpserver.c:95
unsigned long maxconip
Definition tcpserver.c:72
char * fnrules
Definition tcpserver.c:140
int flagallownorules
Definition tcpserver.c:139
char localipstr[IP6_FMT]
Definition tcpserver.c:49
void found(char *data, unsigned int datalen)
Definition tcpserver.c:175
uint16 localport
Definition tcpserver.c:46
char remoteportstr[FMT_ULONG]
Definition tcpserver.c:55
char localportstr[FMT_ULONG]
Definition tcpserver.c:47
unsigned long uid
Definition tcpserver.c:369
char localip[16]
Definition tcpserver.c:48
char * localhost
Definition tcpserver.c:51
unsigned long gid
Definition tcpserver.c:370
int flagkillopts
Definition tcpserver.c:34
void printstatus(void)
Definition tcpserver.c:372
char remoteipstr[IP6_FMT]
Definition tcpserver.c:57
void safecats(char *s)
Definition tcpserver.c:151
void env(const char *s, const char *t)
Definition tcpserver.c:166
void append(char *ch)
Definition tcpserver.c:147
unsigned long numchildren
Definition tcpserver.c:70
GEN_ALLOC_typedef(GEN_ALLOC_readyplus(child_alloc, GEN_ALLOC_readyplus(struct child, GEN_ALLOC_readyplus(c, GEN_ALLOC_readyplus(len, GEN_ALLOC_readyplus(a)
Definition tcpserver.c:89
unsigned long backlog
Definition tcpserver.c:368
void drop_rules(const char *fnbase)
Definition tcpserver.c:170
int flagdeny
Definition tcpserver.c:137
const char * thishost
Definition tcpserver.c:52
uint16 remoteport
Definition tcpserver.c:54
void doit(int t)
Definition tcpserver.c:206
char remoteip[16]
Definition tcpserver.c:56
char * fniprules
Definition tcpserver.c:141
unsigned long limit
Definition tcpserver.c:69
void cats(char *s)
Definition tcpserver.c:143
void ipchild_clear(char ip[16])
Definition tcpserver.c:112
char * remotehost
Definition tcpserver.c:59
int ipchild_limit(char ip[16], unsigned long n)
Definition tcpserver.c:125
int flagallow
Definition tcpserver.c:138
void usage(void)
Definition tcpserver.c:351
int flagdualstack
Definition tcpserver.c:42
int flagparanoid
Definition tcpserver.c:39
char * banner
Definition tcpserver.c:36
int flag1
Definition tcpserver.c:367
int rules(void(*callback)(char *, unsigned int), int fd, char *ip, char *host, char *info)
Definition rules.c:135
int main()
Definition addcr.c:4
char pid[FMT_ULONG]
Definition recordio.c:15
int verbosity
Definition tcpclient.c:45
int flagremotehost
Definition tcpclient.c:48
int flagremoteinfo
Definition tcpclient.c:47
const char * hostname
Definition tcpclient.c:60
int flagdelay
Definition tcpclient.c:46
uint32 netif
Definition tcpclient.c:51
void found(char *data, unsigned int datalen)
int remoteinfo(stralloc *out, char ipremote[16], uint16 portremote, char iplocal[16], uint16 portlocal, unsigned int timeout, uint32 netif)
Definition remoteinfo.c:97
stralloc data
Definition tcprules.c:28
#define WHO
Definition argv0.c:4
char ipaddr[16]
Definition tcpserver.c:85
uint32 num
Definition tcpserver.c:86