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