1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <unistd.h>
5 #include "dns.h"
6 #include "socket.h"
7 #include "ip4.h"
8 #include "ipsvd_log.h"
9 #include "ipsvd_check.h"
10 #include "ipsvd_fmt.h"
11 #include "ipsvd_hostname.h"
12 #include "ipsvd_scan.h"
13 #include "uidgid.h"
14 #include "sgetopt.h"
15 #include "sig.h"
16 #include "str.h"
17 #include "fmt.h"
18 #include "error.h"
19 #include "strerr.h"
20 #include "prot.h"
21 #include "ndelay.h"
22 #include "scan.h"
23 #include "fd.h"
24 #include "wait.h"
25 #include "pathexec.h"
26 
27 #define USAGE " [-hpv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog"
28 #define VERSION "$Id: 4991b38bba93e925f0772eaf9b0b96f5788b009a $"
29 
30 #define FATAL "udpsvd: fatal: "
31 #define WARNING "udpsvd: warning: "
32 #define INFO "udpsvd: info: "
33 #define DROP "udpsvd: drop: "
34 
35 const char *progname;
36 
37 const char **prog;
38 const char *instructs =0;
39 unsigned int iscdb =0;
40 unsigned int verbose =0;
41 unsigned int lookuphost =0;
42 unsigned int paranoid =0;
43 unsigned long timeout =0;
44 
45 static stralloc local_hostname ={0};
46 char local_ip[IP4_FMT];
47 char *local_port;
48 static stralloc remote_hostname ={0};
49 char remote_ip[IP4_FMT];
50 char remote_port[FMT_ULONG];
51 struct uidgid ugid;
52 
53 static char seed[128];
54 struct sockaddr_in socka;
55 int socka_size =sizeof(socka);
56 char bufnum[FMT_ULONG];
57 int s;
58 
59 static stralloc sa ={0};
60 static stralloc ips ={0};
61 static stralloc fqdn ={0};
62 static stralloc inst ={0};
63 static stralloc match ={0};
64 
usage()65 void usage() { strerr_die4x(111, "usage: ", progname, USAGE, "\n"); }
die_nomem()66 void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); }
fatal(char * m0)67 void fatal(char *m0) { strerr_die3sys(111, FATAL, m0, ": "); };
fatal2(char * m0,char * m1)68 void fatal2(char *m0, char *m1) {
69   strerr_die5sys(111, FATAL, m0, ": ", m1, ": ");
70 }
warn(char * m0)71 void warn(char *m0) { strerr_warn3(WARNING, m0, ": ", &strerr_sys); }
warn2(char * m0,char * m1)72 void warn2(char *m0, char *m1) {
73   strerr_warn5(WARNING, m0, ": ", m1, ": ", &strerr_sys);
74 }
drop_nomem()75 void drop_nomem() { strerr_die2x(111, DROP, "out of memory."); }
drop(char * m0)76 void drop(char *m0) { strerr_die3sys(111, DROP, m0, ": "); }
discard(char * m0,char * m1)77 void discard(char *m0, char *m1) {
78   recv(s, 0, 0, 0);
79   strerr_die6sys(111, DROP, "discard data: ", m0, ": ", m1, ": ");
80 }
81 
sig_term_handler()82 void sig_term_handler() {
83   if (verbose) {
84     out(INFO); flush("sigterm received, exit.\n");
85   }
86   _exit(0);
87 }
88 
connection_accept(int c)89 void connection_accept(int c) {
90   int ac;
91   const char **run;
92   const char *args[4];
93   char *ip =(char*)&socka.sin_addr;
94 
95   remote_ip[ipsvd_fmt_ip(remote_ip, ip)] =0;
96   if (verbose) {
97     out(INFO); out("pid ");
98     bufnum[fmt_ulong(bufnum, getpid())] =0;
99     out(bufnum); out(" from "); outfix(remote_ip); flush("\n");
100   }
101   remote_port[ipsvd_fmt_port(remote_port, (char*)&socka.sin_port)] =0;
102   if (lookuphost) {
103     if (ipsvd_hostname(&remote_hostname, ip, paranoid) == -1)
104       warn2("unable to look up hostname", remote_ip);
105     if (! stralloc_0(&remote_hostname)) drop_nomem();
106   }
107 
108   if (instructs) {
109     ac =ipsvd_check(iscdb, &inst, &match, (char*)instructs,
110                     remote_ip, remote_hostname.s, timeout);
111     if (ac == -1) discard("unable to check inst", remote_ip);
112     if (ac == IPSVD_ERR) discard("unable to read", (char*)instructs);
113   }
114   else ac =IPSVD_DEFAULT;
115 
116   if (verbose) {
117     out(INFO);
118     switch(ac) {
119     case IPSVD_DENY: out("deny "); break;
120     case IPSVD_DEFAULT: case IPSVD_INSTRUCT: out("start "); break;
121     case IPSVD_EXEC: out("exec "); break;
122     }
123     bufnum[fmt_ulong(bufnum, getpid())] =0;
124     out(bufnum); out(" ");
125     outfix(local_hostname.s); out(":"); out(local_ip);
126     out(" :"); outfix(remote_hostname.s); out(":");
127     outfix(remote_ip); out(":"); outfix(remote_port);
128     if (instructs) {
129       out(" ");
130       if (iscdb) {
131         out((char*)instructs); out("/");
132       }
133       outfix(match.s);
134       if(inst.s && inst.len && (verbose > 1)) {
135         out(": "); outinst(&inst);
136       }
137     }
138     flush("\n");
139   }
140 
141   if (ac == IPSVD_DENY) {
142     recv(s, 0, 0, 0);
143     _exit(100);
144   }
145   if (ac == IPSVD_EXEC) {
146     args[0] ="/bin/sh"; args[1] ="-c"; args[2] =inst.s; args[3] =0;
147     run =args;
148   }
149   else run =prog;
150 
151   if ((fd_move(0, c) == -1) || (fd_copy(1, 2) == -1))
152     drop("unable to set filedescriptor");
153   sig_uncatch(sig_term);
154   sig_uncatch(sig_pipe);
155   pathexec(run);
156 
157   discard("unable to run", (char*)*prog);
158 }
159 
main(int argc,const char ** argv,const char * const * envp)160 int main(int argc, const char **argv, const char *const *envp) {
161   int opt;
162   char *user =0;
163   char *host;
164   unsigned long port;
165   int pid;
166   int wstat;
167   iopause_fd io[1];
168   struct taia now;
169   struct taia deadline;
170 
171   progname =*argv;
172 
173   while ((opt =getopt(argc, argv, "vu:l:hpi:x:t:V")) != opteof) {
174     switch(opt) {
175     case 'v':
176       ++verbose;
177       break;
178     case 'u':
179       user =(char*)optarg;
180       break;
181     case 'l':
182       if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
183       if (! stralloc_0(&local_hostname)) die_nomem();
184       break;
185     case 'h':
186       lookuphost =1;
187       break;
188     case 'p':
189       lookuphost =1;
190       paranoid =1;
191       break;
192     case 'i':
193       if (instructs) usage();
194       instructs =optarg;
195       break;
196     case 'x':
197       if (instructs) usage();
198       instructs =optarg;
199       iscdb =1;
200       break;
201     case 't':
202       scan_ulong(optarg, &timeout);
203       break;
204     case 'V':
205       strerr_warn1(VERSION, 0);
206     case '?':
207       usage();
208     }
209   }
210   argv +=optind;
211 
212   if (! argv || ! *argv) usage();
213   host =(char*)*argv++;
214   if (! argv || ! *argv) usage();
215   local_port =(char*)*argv++;
216   if (! argv || ! *argv) usage();
217   prog =argv;
218 
219   if (user)
220     if (! uidgids_get(&ugid, user))
221       strerr_die3x(100, FATAL, "unknown user/group: ", user);
222 
223   dns_random_init(seed);
224   sig_catch(sig_term, sig_term_handler);
225   sig_ignore(sig_pipe);
226 
227   if (str_equal(host, "")) host ="0.0.0.0";
228   if (str_equal(host, "0")) host ="0.0.0.0";
229 
230   if (! ipsvd_scan_port(local_port, "udp", &port))
231     strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);
232 
233   if (! stralloc_copys(&sa, host)) die_nomem();
234   if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
235     if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
236       fatal2("unable to look up ip address", host);
237   if (ips.len < 4)
238     strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
239   ips.len =4;
240   if (! stralloc_0(&ips)) die_nomem();
241   local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;
242   if (! local_hostname.len) {
243     if (dns_name4(&local_hostname, ips.s) == -1)
244       fatal("unable to look up local hostname");
245     if (! stralloc_0(&local_hostname)) die_nomem();
246   }
247 
248   if (! lookuphost) {
249     if (! stralloc_copys(&remote_hostname, "")) die_nomem();
250     if (! stralloc_0(&remote_hostname)) die_nomem();
251   }
252 
253   if ((s =socket_udp()) == -1) fatal("unable to create socket");
254   if (socket_bind4_reuse(s, ips.s, port) == -1)
255     fatal("unable to bind socket");
256   ndelay_off(s);
257 
258   if (user) { /* drop permissions */
259     if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
260     if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
261     if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
262   }
263   close(0);
264 
265   if (verbose) {
266     out(INFO); out("listening on "); outfix(local_ip); out(":");
267     outfix(local_port);
268     if (user) {
269       bufnum[fmt_ulong(bufnum, ugid.uid)] =0;
270       out(", uid "); out(bufnum);
271       bufnum[fmt_ulong(bufnum, ugid.gid)] =0;
272       out(", gid "); out(bufnum);
273     }
274     flush(", starting.\n");
275   }
276 
277   io[0].fd =s;
278   io[0].events =IOPAUSE_READ;
279   io[0].revents =0;
280   for (;;) {
281     taia_now(&now);
282     taia_uint(&deadline, 3600);
283     taia_add(&deadline, &now, &deadline);
284     iopause(io, 1, &deadline, &now);
285 
286     if (io[0].revents | IOPAUSE_READ) {
287       io[0].revents =0;
288       while ((pid =fork()) == -1) {
289         warn("unable to fork, sleeping");
290         sleep(5);
291       }
292       if (pid == 0) { /* child */
293         if (recvfrom(s, 0, 0, MSG_PEEK, (struct sockaddr *)&socka,
294                      &socka_size) == -1) drop("unable to read from socket");
295         connection_accept(s);
296       }
297       while (wait_pid(&wstat, pid) == -1) warn("error waiting for child");
298       if (verbose) {
299         out(INFO); out("end ");
300         bufnum[fmt_ulong(bufnum, pid)] =0;
301         out(bufnum); flush("\n");
302       }
303     }
304   }
305   _exit(0);
306 }
307