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