xref: /plan9/sys/src/cmd/aux/trampoline.c (revision 5741f218aafa73850887bbdc807950a4a496c955)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ndb.h>
5 #include <fcall.h>
6 
7 enum
8 {
9 	Maxpath=	128,
10 };
11 
12 typedef struct Endpoints Endpoints;
13 struct Endpoints
14 {
15 	char 	*net;
16 	char	*lsys;
17 	char	*lserv;
18 	char	*rsys;
19 	char	*rserv;
20 };
21 
22 void		xfer(int, int);
23 void		xfer9p(int, int);
24 Endpoints*	getendpoints(char*);
25 void		freeendpoints(Endpoints*);
26 char*		iptomac(char*, char*);
27 int		macok(char*);
28 
29 void
usage(void)30 usage(void)
31 {
32 	fprint(2, "usage: trampoline [-9] [-a addr] [-m netdir] addr\n");
33 	exits("usage");
34 }
35 
36 void
main(int argc,char ** argv)37 main(int argc, char **argv)
38 {
39 	char *altaddr, *checkmac, *mac;
40 	int fd, fd0, fd1;
41 	void (*x)(int, int);
42 	Endpoints *ep;
43 
44 	checkmac = nil;
45 	altaddr = nil;
46 	x = xfer;
47 	ARGBEGIN{
48 	case '9':
49 		x = xfer9p;
50 		break;
51 	case 'a':
52 		altaddr = EARGF(usage());
53 		break;
54 	case 'm':
55 		checkmac = EARGF(usage());
56 		break;
57 	default:
58 		usage();
59 	}ARGEND;
60 
61 	if(argc != 1)
62 		usage();
63 
64 	if(checkmac){
65 		ep = getendpoints(checkmac);
66 		mac = iptomac(ep->rsys, ep->net);
67 		if(!macok(mac)){
68 			syslog(0, "trampoline", "badmac %s from %s!%s for %s!%s on %s",
69 				mac, ep->rsys, ep->rserv, ep->lsys, ep->lserv, ep->net);
70 			exits("bad mac");
71 		}
72 	}
73 
74 	fd0 = 0;
75 	fd1 = 1;
76 	if(altaddr){
77 		fd0 = dial(altaddr, 0, 0, 0);
78 		if(fd0 < 0)
79 			sysfatal("dial %s: %r", altaddr);
80 		fd1 = fd0;
81 	}
82 	fd = dial(argv[0], 0, 0, 0);
83 	if(fd < 0)
84 		sysfatal("dial %s: %r", argv[0]);
85 
86 	rfork(RFNOTEG);
87 	switch(fork()){
88 	case -1:
89 		fprint(2, "%s: fork: %r\n", argv0);
90 		exits("dial");
91 	case 0:
92 		(*x)(fd0, fd);
93 		break;
94 	default:
95 		(*x)(fd, fd1);
96 		break;
97 	}
98 	postnote(PNGROUP, getpid(), "die yankee pig dog");
99 	exits(0);
100 }
101 
102 void
xfer(int from,int to)103 xfer(int from, int to)
104 {
105 	char buf[12*1024];
106 	int n;
107 
108 	while((n = read(from, buf, sizeof buf)) > 0)
109 		if(write(to, buf, n) < 0)
110 			break;
111 }
112 
113 void
xfer9p(int from,int to)114 xfer9p(int from, int to)
115 {
116 	uchar *buf;
117 	uint nbuf;
118 	int n;
119 
120 	nbuf = 256;
121 	buf = malloc(nbuf);
122 	if(buf == nil)
123 		sysfatal("xfer: malloc %ud: %r", nbuf);
124 
125 	for(;;){
126 		if(readn(from, buf, 4) != 4)
127 			break;
128 		n = GBIT32(buf);
129 		if(n > nbuf){
130 			nbuf = n+8192;
131 			buf = realloc(buf, nbuf);
132 			if(buf == nil)
133 				sysfatal("xfer: realloc %ud: %r", nbuf);
134 		}
135 		if(readn(from, buf+4, n-4) != n-4)
136 			break;
137 		if(write(to, buf, n) != n){
138 			sysfatal("oops: %r");
139 			break;
140 		}
141 	}
142 }
143 
144 void
getendpoint(char * dir,char * file,char ** sysp,char ** servp)145 getendpoint(char *dir, char *file, char **sysp, char **servp)
146 {
147 	int fd, n;
148 	char buf[Maxpath];
149 	char *sys, *serv;
150 
151 	sys = serv = 0;
152 
153 	snprint(buf, sizeof buf, "%s/%s", dir, file);
154 	fd = open(buf, OREAD);
155 	if(fd >= 0){
156 		n = read(fd, buf, sizeof(buf)-1);
157 		if(n>0){
158 			buf[n-1] = 0;
159 			serv = strchr(buf, '!');
160 			if(serv){
161 				*serv++ = 0;
162 				serv = strdup(serv);
163 			}
164 			sys = strdup(buf);
165 		}
166 		close(fd);
167 	}
168 	if(serv == 0)
169 		serv = strdup("unknown");
170 	if(sys == 0)
171 		sys = strdup("unknown");
172 	*servp = serv;
173 	*sysp = sys;
174 }
175 
176 Endpoints *
getendpoints(char * dir)177 getendpoints(char *dir)
178 {
179 	Endpoints *ep;
180 	char *p;
181 
182 	ep = malloc(sizeof(*ep));
183 	ep->net = strdup(dir);
184 	p = strchr(ep->net+1, '/');
185 	if(p == nil){
186 		free(ep->net);
187 		ep->net = "/net";
188 	} else
189 		*p = 0;
190 	getendpoint(dir, "local", &ep->lsys, &ep->lserv);
191 	getendpoint(dir, "remote", &ep->rsys, &ep->rserv);
192 	return ep;
193 }
194 
195 void
freeendpoints(Endpoints * ep)196 freeendpoints(Endpoints *ep)
197 {
198 	free(ep->lsys);
199 	free(ep->rsys);
200 	free(ep->lserv);
201 	free(ep->rserv);
202 	free(ep);
203 }
204 
205 char*
iptomac(char * ip,char * net)206 iptomac(char *ip, char *net)
207 {
208 	char file[Maxpath];
209 	Biobuf *b;
210 	char *p;
211 	char *f[5];
212 
213 	snprint(file, sizeof(file), "%s/arp", net);
214 	b = Bopen(file, OREAD);
215 	if(b == nil)
216 		return nil;
217 	while((p = Brdline(b, '\n')) != nil){
218 		p[Blinelen(b)-1] = 0;
219 		if(tokenize(p, f, nelem(f)) < 4)
220 			continue;
221 		if(strcmp(f[1], "OK") == 0
222 		&& strcmp(f[2], ip) == 0){
223 			p = strdup(f[3]);
224 			Bterm(b);
225 			return p;
226 		}
227 	}
228 	Bterm(b);
229 	return nil;
230 }
231 
232 int
macok(char * mac)233 macok(char *mac)
234 {
235 	char *p;
236 
237 	if(mac == nil)
238 		return 0;
239 	free(p = csgetvalue("/net", "ether", mac, "trampok", nil));
240 	return !(p == nil);
241 }
242