|
|
teed.c - teed - A multiplex relay tee(1) daemon. |
|
|
 |
git clone git://bitreich.org/teed git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/teed (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
teed.c (5223B) |
|
|
|
--- |
|
|
|
1 /* |
|
|
|
2 * See LICENSE file for license information. |
|
|
|
3 * |
|
|
|
4 * Copy me if you can. |
|
|
|
5 * by 20h |
|
|
|
6 */ |
|
|
|
7 |
|
|
|
8 #include <unistd.h> |
|
|
|
9 #include <stdio.h> |
|
|
|
10 #include <stdlib.h> |
|
|
|
11 #include <string.h> |
|
|
|
12 #include <sys/socket.h> |
|
|
|
13 #include <sys/un.h> |
|
|
|
14 #include <signal.h> |
|
|
|
15 #include <errno.h> |
|
|
|
16 #include <sys/stat.h> |
|
|
|
17 #include <sys/select.h> |
|
|
|
18 |
|
|
|
19 volatile sig_atomic_t isrunning = 1; |
|
|
|
20 |
|
|
|
21 void * |
|
|
|
22 memdup(void *p, int l) |
|
|
|
23 { |
|
|
|
24 char *ret; |
|
|
|
25 |
|
|
|
26 ret = calloc(1, l); |
|
|
|
27 if (ret == NULL) { |
|
|
|
28 perror("calloc"); |
|
|
|
29 exit(1); |
|
|
|
30 } |
|
|
|
31 memcpy(ret, p, l); |
|
|
|
32 |
|
|
|
33 return (void *)ret; |
|
|
|
34 } |
|
|
|
35 |
|
|
|
36 typedef struct llist llist; |
|
|
|
37 struct llist { |
|
|
|
38 llist *prev; |
|
|
|
39 llist *next; |
|
|
|
40 int dlen; |
|
|
|
41 void *data; |
|
|
|
42 }; |
|
|
|
43 |
|
|
|
44 #define forllist(list, elem) for (elem = list;\ |
|
|
|
45 elem; elem = elem->next) |
|
|
|
46 |
|
|
|
47 void |
|
|
|
48 closeallfds(llist *fds) |
|
|
|
49 { |
|
|
|
50 llist *e; |
|
|
|
51 |
|
|
|
52 forllist(fds, e) |
|
|
|
53 close(*(int *)e->data); |
|
|
|
54 } |
|
|
|
55 |
|
|
|
56 void |
|
|
|
57 llist_free1(llist *l) |
|
|
|
58 { |
|
|
|
59 if (l == NULL) |
|
|
|
60 return; |
|
|
|
61 free(l->data); |
|
|
|
62 l->data = NULL; |
|
|
|
63 l->next = NULL; |
|
|
|
64 l->prev = NULL; |
|
|
|
65 free(l); |
|
|
|
66 } |
|
|
|
67 |
|
|
|
68 void |
|
|
|
69 llist_free(llist *l) |
|
|
|
70 { |
|
|
|
71 llist *tl; |
|
|
|
72 |
|
|
|
73 while (l != NULL) { |
|
|
|
74 tl = l->next; |
|
|
|
75 llist_free1(l); |
|
|
|
76 l = tl; |
|
|
|
77 } |
|
|
|
78 } |
|
|
|
79 |
|
|
|
80 llist * |
|
|
|
81 llist_new(llist *prev, llist *next, void *data, int len) |
|
|
|
82 { |
|
|
|
83 llist *ret; |
|
|
|
84 |
|
|
|
85 ret = calloc(1, sizeof(llist)); |
|
|
|
86 if (ret == NULL) { |
|
|
|
87 perror("calloc"); |
|
|
|
88 exit(1); |
|
|
|
89 } |
|
|
|
90 ret->prev = prev; |
|
|
|
91 ret->next = next; |
|
|
|
92 if (data != NULL) { |
|
|
|
93 ret->data = memdup(data, len); |
|
|
|
94 ret->dlen = len; |
|
|
|
95 } else { |
|
|
|
96 ret->data = NULL; |
|
|
|
97 ret->dlen = 0; |
|
|
|
98 } |
|
|
|
99 |
|
|
|
100 return ret; |
|
|
|
101 } |
|
|
|
102 |
|
|
|
103 int |
|
|
|
104 llist_len(llist *l) |
|
|
|
105 { |
|
|
|
106 int llistl = 0; |
|
|
|
107 for (;l != NULL; l = l->next) |
|
|
|
108 llistl++; |
|
|
|
109 return llistl; |
|
|
|
110 } |
|
|
|
111 |
|
|
|
112 llist * |
|
|
|
113 llist_put(llist *l, void *data, int len) |
|
|
|
114 { |
|
|
|
115 llist *ol; |
|
|
|
116 |
|
|
|
117 if (l == NULL) |
|
|
|
118 return llist_new(NULL, NULL, data, len); |
|
|
|
119 |
|
|
|
120 ol = l; |
|
|
|
121 for (; l->next; l = l->next); |
|
|
|
122 l->next = llist_new(l, NULL, data, len); |
|
|
|
123 |
|
|
|
124 return ol; |
|
|
|
125 } |
|
|
|
126 |
|
|
|
127 llist * |
|
|
|
128 llist_del(llist **l, llist *e) |
|
|
|
129 { |
|
|
|
130 llist *enext, *eprev; |
|
|
|
131 |
|
|
|
132 enext = e->next; |
|
|
|
133 eprev = e->prev; |
|
|
|
134 if (enext != NULL) |
|
|
|
135 enext->prev = eprev; |
|
|
|
136 if (eprev != NULL) |
|
|
|
137 eprev->next = enext; |
|
|
|
138 llist_free1(e); |
|
|
|
139 |
|
|
|
140 if (*l == e) |
|
|
|
141 *l = enext; |
|
|
|
142 |
|
|
|
143 if (eprev != NULL) |
|
|
|
144 return eprev; |
|
|
|
145 if (enext != NULL) |
|
|
|
146 return enext; |
|
|
|
147 return NULL; |
|
|
|
148 } |
|
|
|
149 |
|
|
|
150 void |
|
|
|
151 sighandler(int signo) |
|
|
|
152 { |
|
|
|
153 switch (signo) { |
|
|
|
154 case SIGINT: |
|
|
|
155 case SIGTERM: |
|
|
|
156 isrunning = 0; |
|
|
|
157 break; |
|
|
|
158 } |
|
|
|
159 } |
|
|
|
160 |
|
|
|
161 void |
|
|
|
162 initsignals(void) |
|
|
|
163 { |
|
|
|
164 signal(SIGPIPE, SIG_IGN); |
|
|
|
165 signal(SIGINT, sighandler); |
|
|
|
166 signal(SIGTERM, sighandler); |
|
|
|
167 } |
|
|
|
168 |
|
|
|
169 int |
|
|
|
170 main(int argc, char *argv[]) |
|
|
|
171 { |
|
|
|
172 int on, i, maxsfd, afd, rval, recvl, |
|
|
|
173 sendl, sent, lfd; |
|
|
|
174 struct sockaddr_un saddrs[2], clt; |
|
|
|
175 char *bindpaths[2] = {"in", "out"}, |
|
|
|
176 recvbuf[4*1024], |
|
|
|
177 *sendbufi; |
|
|
|
178 llist *wfds, *rfds, *lfds, *e, *qe; |
|
|
|
179 socklen_t saddrlen, cltlen; |
|
|
|
180 fd_set fdset; |
|
|
|
181 struct timespec timeout; |
|
|
|
182 |
|
|
|
183 initsignals(); |
|
|
|
184 |
|
|
|
185 rval = 1; |
|
|
|
186 rfds = NULL; |
|
|
|
187 wfds = NULL; |
|
|
|
188 lfds = NULL; |
|
|
|
189 |
|
|
|
190 on = 1; |
|
|
|
191 for (i = 0; i < 2; i++) { |
|
|
|
192 lfd = socket(AF_UNIX, SOCK_STREAM, 0); |
|
|
|
193 if (lfd < 0) { |
|
|
|
194 perror("socket"); |
|
|
|
195 goto stop_serving; |
|
|
|
196 } |
|
|
|
197 if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, |
|
|
|
198 &on, sizeof(on)) < 0) { |
|
|
|
199 perror("setsockopt"); |
|
|
|
200 goto stop_serving; |
|
|
|
201 } |
|
|
|
202 |
|
|
|
203 if (access(bindpaths[i], F_OK) == 0) { |
|
|
|
204 if (remove(bindpaths[i]) < 0) { |
|
|
|
205 perror("remove"); |
|
|
|
206 goto stop_serving; |
|
|
|
207 } |
|
|
|
208 } |
|
|
|
209 |
|
|
|
210 saddrs[i].sun_family = AF_UNIX; |
|
|
|
211 strncpy(saddrs[i].sun_path, bindpaths[i], |
|
|
|
212 sizeof(bindpaths[i])-1); |
|
|
|
213 saddrlen = sizeof(saddrs[i]); |
|
|
|
214 |
|
|
|
215 if (bind(lfd, (struct sockaddr *)&saddrs[i], saddrlen) < 0) { |
|
|
|
216 perror("bind"); |
|
|
|
217 goto stop_serving; |
|
|
|
218 } |
|
|
|
219 |
|
|
|
220 if (chmod(bindpaths[i], 0775) < 0) { |
|
|
|
221 perror("chmod"); |
|
|
|
222 goto stop_serving; |
|
|
|
223 } |
|
|
|
224 |
|
|
|
225 if (listen(lfd, 255) < 0) { |
|
|
|
226 perror("listen"); |
|
|
|
227 goto stop_serving; |
|
|
|
228 } |
|
|
|
229 |
|
|
|
230 lfds = llist_put(lfds, &lfd, sizeof(lfd)); |
|
|
|
231 } |
|
|
|
232 |
|
|
|
233 timeout.tv_sec = 1; |
|
|
|
234 timeout.tv_nsec = 0; |
|
|
|
235 for (;isrunning;) { |
|
|
|
236 maxsfd = 0; |
|
|
|
237 FD_ZERO(&fdset); |
|
|
|
238 forllist(lfds, e) { |
|
|
|
239 FD_SET(*(int *)e->data, &fdset); |
|
|
|
240 if (*(int *)e->data > maxsfd) |
|
|
|
241 maxsfd = *(int *)e->data; |
|
|
|
242 } |
|
|
|
243 forllist(rfds, e) { |
|
|
|
244 FD_SET(*(int *)e->data, &fdset); |
|
|
|
245 if (*(int *)e->data > maxsfd) |
|
|
|
246 maxsfd = *(int *)e->data; |
|
|
|
247 } |
|
|
|
248 |
|
|
|
249 if (pselect(maxsfd+1, &fdset, NULL, NULL, &timeout, NULL) < 0) { |
|
|
|
250 if (errno == EINTR) |
|
|
|
251 continue; |
|
|
|
252 perror("pselect"); |
|
|
|
253 goto stop_serving; |
|
|
|
254 } |
|
|
|
255 |
|
|
|
256 i = -1; |
|
|
|
257 forllist(lfds, e) { |
|
|
|
258 i++; |
|
|
|
259 if (FD_ISSET(*(int *)e->data, &fdset)) { |
|
|
|
260 cltlen = sizeof(clt); |
|
|
|
261 afd = accept(*(int *)e->data, |
|
|
|
262 (struct sockaddr *)&clt, |
|
|
|
263 &cltlen); |
|
|
|
264 if (afd < 0 && errno != ECONNABORTED |
|
|
|
265 && errno != EINTR) { |
|
|
|
266 perror("accept"); |
|
|
|
267 goto stop_serving; |
|
|
|
268 } |
|
|
|
269 |
|
|
|
270 if (i == 0) { |
|
|
|
271 rfds = llist_put(rfds, &afd, |
|
|
|
272 sizeof(afd)); |
|
|
|
273 } else { |
|
|
|
274 wfds = llist_put(wfds, &afd, |
|
|
|
275 sizeof(afd)); |
|
|
|
276 } |
|
|
|
277 } |
|
|
|
278 } |
|
|
|
279 |
|
|
|
280 forllist(rfds, e) { |
|
|
|
281 if (FD_ISSET(*(int *)e->data, &fdset)) { |
|
|
|
282 recvl = read(*(int *)e->data, recvbuf, |
|
|
|
283 sizeof(recvbuf)); |
|
|
|
284 if (recvl <= 0) { |
|
|
|
285 close(*(int *)e->data); |
|
|
|
286 e = llist_del(&rfds, e); |
|
|
|
287 if (e == NULL) |
|
|
|
288 break; |
|
|
|
289 } |
|
|
|
290 |
|
|
|
291 forllist(wfds, qe) { |
|
|
|
292 sendbufi = recvbuf; |
|
|
|
293 sendl = recvl; |
|
|
|
294 while (sendl > 0) { |
|
|
|
295 if ((sent = write(*(int *)qe->data, sendbufi, sendl)) < 0) { |
|
|
|
296 close(*(int *)qe->data); |
|
|
|
297 qe = llist_del(&wfds, qe); |
|
|
|
298 break; |
|
|
|
299 } |
|
|
|
300 sendl -= sent; |
|
|
|
301 sendbufi += sent; |
|
|
|
302 } |
|
|
|
303 if (qe == NULL) |
|
|
|
304 break; |
|
|
|
305 } |
|
|
|
306 } |
|
|
|
307 } |
|
|
|
308 |
|
|
|
309 } |
|
|
|
310 |
|
|
|
311 rval = 0; |
|
|
|
312 stop_serving: |
|
|
|
313 closeallfds(lfds); |
|
|
|
314 llist_free(lfds); |
|
|
|
315 closeallfds(rfds); |
|
|
|
316 llist_free(rfds); |
|
|
|
317 closeallfds(wfds); |
|
|
|
318 llist_free(wfds); |
|
|
|
319 |
|
|
|
320 return rval; |
|
|
|
321 } |
|
|
|
322 |
|