2 * Encrypting tunnel for userv-ipif tunnels, actual implementation
5 * udptunnel-forwarder <optchars>
6 * <public-local-fd> <private-in-fd> <private-out-fd>
8 * <mtu> <keepalive> <timeout>
9 * <public-remote-addr> [<public-remote-port>]
10 * <mech1> [<mech1-params> ...]
11 * <mech2> [<mech2-params> ...]
14 * Remote addr may '' to mean wait to receive a packet and reply to
15 * whereever we get a good packet from first, in which case port
16 * should not be specified.
18 * <optchars> is zero or more of
19 * w means generate and write encdec keys, rather than reading them
20 * D means do crypto debug (use with care!)
22 * Every must be numeric. There is very little argument checking.
26 * 0 terminated due to outbound packet stream EOF
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <sys/utsname.h>
47 #include "forwarder.h"
51 static size_t buffer_size
;
53 static const char *opt_chars
;
54 static int public_local_fd
, private_in_fd
, private_out_fd
;
55 static int mtu2
, keepalive
, timeout
;
56 static int public_remote_specd
;
57 static struct sockaddr_in public_remote
;
58 static int encdec_keys_fd
, encdec_keys_write
, crypto_debug
;
60 static const struct mechanism
*mechs
[MAXMECHS
];
62 static struct mechdata
*md_in
[MAXMECHS
], *md_out
[MAXMECHS
];
63 static size_t maxprefix
, maxsuffix
;
65 static struct buffer buf_in
, buf_out
;
66 static unsigned char *accum_buf
;
67 static size_t accum_used
, accum_avail
;
69 static time_t nextsendka
;
71 static void cdebug(int mechno
/*or -1*/, const char *msg
) {
72 if (!crypto_debug
) return;
73 printf("%s: CRYPTO: %-20s encrypt setup\n",
75 mechno
>= 0 ? mechs
[i
]->name
: "",
79 static void cdebughex(int mechno
/*or -1*/, const char *msg
,
80 size_t skipbefore
, const void *ptr
, size_t sz
, size_t skipafter
) {
81 const unsigned char *p
;
83 if (!crypto_debug
) return;
84 printf("%s: CRYPTO: %-20s %s",
86 mechno
>= 0 ? mechs
[i
]->name
: "",
88 for (i
=0; i
<skipbefore
) fputs(" ..",stdout
);
89 for (i
=0, p
=ptr
; i
<sz
; i
++, p
++) fprintf(" %02x",*p
);
90 for (i
=0; i
<skipafter
) fputs(" ..",stdout
);
94 void get_random(void *ptr
, size_t sz
) {
95 static FILE *randfile
;
100 randfile
= fopen("/dev/urandom","rb");
101 if (!randfile
&& errno
==ENOENT
) randfile
= fopen("/dev/random","rb");
102 if (!randfile
) sysfail("open random number generator");
105 r
= fread(ptr
,1,sz
,randfile
);
107 (ferror(randfile
) ? sysfail
: fail
)("cannot read random number generator");
109 cdebughex(-1, "get_random", ptr
, sz
, 0,0);
112 void random_key(void *ptr
, size_t sz
) {
113 if (encdec_keys_write
) {
115 write_must(encdec_keys_fd
,ptr
,sz
,"write keys datastream");
117 read_must(encdec_keys_fd
,ptr
,sz
,"read keys datastream");
122 static void setnonblock(int fd
, int nonblock
) {
125 r
= fcntl(fd
,F_GETFL
);
126 if (r
==-1) sysfail("fcntl F_GETFL");
127 r
= fcntl(fd
,F_SETFL
, nonblock ? r
|O_NONBLOCK
: r
&~O_NONBLOCK
);
128 if (r
==-1) sysfail("fcntl F_SETFL");
131 static const struct mechanism
*getarg_mech(void) {
133 const struct mechanism
*mech
, *const *mechlist
;
135 name
= getarg_string();
137 for (mechlist
= mechanismlists
;
140 for (mech
= *mechlist
; mech
->name
; mech
++)
141 if (!strcmp(mech
->name
,name
)) return mech
;
143 fprintf(stderr
,"%s: unknown mechanism: %s\n",programid
,name
);
147 static void inbound(void) {
148 static int any_recvd
;
150 struct sockaddr_in this_saddr
;
151 int r
, i
, different
, this_saddrlen
;
154 buf_in
.start
= buf_in
.base
+1;
155 buf_in
.size
= buffer_size
-2;
157 setnonblock(public_local_fd
,1);
158 this_saddrlen
= sizeof(this_saddr
);
159 r
= recvfrom(public_local_fd
, buf_in
.start
, buf_in
.size
, 0,
160 &this_saddr
, &this_saddrlen
);
161 if (!r
) { diag("empty ciphertext"); return; }
164 if (errno
!= EAGAIN
&& errno
!= EINTR
) { sysdiag("receive"); sleep(1); }
167 if (this_saddr
.sin_family
!= AF_INET
) {
168 fprintf(stderr
,"%s: received unknown AF %lu\n",
169 programid
, (unsigned long)this_saddr
.sin_family
);
172 assert(this_saddrlen
== sizeof(this_saddr
));
174 assert(r
<= buf_in
.size
);
176 for (i
=n_mechs
-1; i
>=0; i
--) {
177 emsg
= mechs
[i
]->decode(md_in
[i
],&buf_in
);
179 fprintf(stderr
, "%s: bad packet: %s: %s\n", programid
, mechs
[i
]->name
, emsg
);
186 different
= (!public_remote_specd
||
187 public_remote
.sin_addr
.s_addr
!= this_saddr
.sin_addr
.s_addr
||
188 public_remote
.sin_port
!= this_saddr
.sin_port
);
192 if (public_remote_specd
==2) {
193 fprintf(stderr
, "%s: packet from unexpected sender %s:%lu\n",
194 programid
, inet_ntoa(this_saddr
.sin_addr
),
195 (unsigned long)ntohs(this_saddr
.sin_port
));
199 fprintf(stderr
, "%s: tunnel open with peer %s:%lu\n",
200 programid
, inet_ntoa(this_saddr
.sin_addr
),
201 (unsigned long)ntohs(this_saddr
.sin_port
));
203 public_remote_specd
= 1;
204 memcpy(&public_remote
,&this_saddr
,sizeof(public_remote
));
206 } else if (!any_recvd
) {
214 if (!buf_in
.size
|| *buf_in
.start
!= 0300) {
215 *--buf_in
.start
= 0300;
218 if (buf_in
.start
[buf_in
.size
-1] != 0300) {
219 buf_in
.start
[buf_in
.size
++]= 0300;
222 setnonblock(private_in_fd
,0);
223 write_must(private_in_fd
, buf_in
.start
, buf_in
.size
, "write down");
226 static void sendpacket(const unsigned char *message
, size_t size
) {
229 buf_out
.start
= buf_out
.base
+maxprefix
;
231 memcpy(buf_out
.start
, message
, size
);
233 nextsendka
= now() + keepalive
;
235 for (i
=0; i
<n_mechs
; i
++) mechs
[i
]->encode(md_out
[i
],&buf_out
);
236 assert(public_remote_specd
);
238 setnonblock(public_local_fd
,1);
240 r
= sendto(public_local_fd
, buf_out
.start
, buf_out
.size
, 0,
241 &public_remote
, sizeof(public_remote
));
242 if (r
== buf_out
.size
) break;
243 if (r
>= 0) { diag("unexpected short send"); return; }
244 if (errno
!= EINTR
) { sysdiag("send"); return; }
248 static void outbound(void) {
250 unsigned char *after_eaten
, *delim
;
253 setnonblock(private_out_fd
,1);
256 r
= read(private_out_fd
, accum_buf
+ accum_used
, accum_avail
- accum_used
);
257 if (!r
) { diag("outbound datastream closed, quitting"); exit(0); }
259 if (errno
== EAGAIN
) return;
260 if (errno
== EINTR
) continue;
263 assert(accum_used
<=accum_avail
);
265 after_eaten
= accum_buf
;
266 while ((delim
= memchr(after_eaten
, 0300, accum_used
))) {
267 this_packet
= delim
- after_eaten
;
268 if (this_packet
) sendpacket(after_eaten
, this_packet
);
269 accum_used
-= this_packet
+1;
270 after_eaten
= delim
+1;
272 memmove(accum_buf
, after_eaten
, accum_used
);
274 if (accum_used
== accum_avail
) {
275 diag("missing interpacket delimiter in output datastream");
281 int main(int argc
, const char *const *const argv_in
) {
283 struct pollfd pollfds
[2];
284 struct utsname uname_result
;
285 int i
, polltimeout
, r
;
290 if (uname(&uname_result
)) { perror(PROGRAM
": uname failed"); exit(16); }
291 sprintf(programid
, PROGRAM
": %.*s", SYS_NMLN
, uname_result
.nodename
);
293 opt_chars
= getarg_string();
294 encdec_keys_write
= !!strchr(opt_chars
,"w");
295 crypto_debug
= !!strchr(opt_chars
,"D");
297 public_local_fd
= getarg_ulong();
298 private_in_fd
= getarg_ulong();
299 private_out_fd
= getarg_ulong();
300 encdec_keys_fd
= getarg_ulong();
302 mtu2
= getarg_ulong() * 2;
303 keepalive
= getarg_ulong();
304 timeout
= getarg_ulong();
306 arg
= getarg_string();
308 public_remote_specd
= 1;
309 public_remote
.sin_family
= AF_INET
;
310 arg_assert(inet_aton(arg
,&public_remote
.sin_addr
));
311 public_remote
.sin_port
= htons(getarg_ulong());
315 diag("crypto debugging enabled!");
316 setvbuf(stdout
,0,_IOLBF
,0);
320 for (i
=0; i
<n_mechs
; i
++) {
321 mechs
[i
]= getarg_mech();
323 for (i
=0; i
<n_mechs
; i
++) {
324 cdebug(i
,"encrypt setup");
325 mechs
[i
]->encsetup(&md_in
[i
], &maxprefix
, &maxsuffix
);
327 for (i
=0; i
<n_mechs
; i
++) {
328 cdebug(i
,"decrypt setup");
329 mechs
[i
]->decsetup(&md_out
[i
]);
332 if (maxprefix
<1) maxprefix
= 1;
333 if (maxsuffix
<1) maxsuffix
= 1;
334 buffer_size
= mtu2
+ maxprefix
+ maxsuffix
;
335 buf_in
.base
= xmalloc(buffer_size
);
336 buf_out
.base
= xmalloc(buffer_size
);
337 accum_avail
= mtu2
+ 1;
338 accum_buf
= xmalloc(accum_avail
);
342 pollfds
[0].fd
= public_local_fd
;
343 pollfds
[0].events
= POLLIN
;
344 pollfds
[1].fd
= private_out_fd
;
346 pollfds
[1].events
= public_remote_specd ? POLLIN
: 0;
347 pollfds
[0].revents
= 0;
348 pollfds
[1].revents
= 0;
352 if (tnow
>= nextsendka
&& public_remote_specd
) sendpacket("\300",1);
353 polltimeout
= (nextsendka
- tnow
)*1000;
358 r
= poll(pollfds
,2,polltimeout
);
360 if (r
==-1 && errno
==EINTR
) continue;
361 if (r
==-1) sysfail("poll");
363 if (pollfds
[0].revents
& (POLLIN
|POLLERR
)) inbound();
364 if (pollfds
[1].revents
& (POLLIN
|POLLERR
)) outbound();