2 * transsip - the telephony network
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
16 #include <sys/types.h>
17 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
22 #include <celt/celt.h>
23 #include <sys/ptrace.h>
24 #include <speex/speex_jitter.h>
25 #include <speex/speex_echo.h>
36 #include "crypto_verify_32.h"
37 #include "crypto_box_curve25519xsalsa20poly1305.h"
38 #include "crypto_scalarmult_curve25519.h"
39 #include "crypto_auth_hmacsha512256.h"
41 noinline
void *memset(void *__s
, int __c
, size_t __n
);
42 extern void enter_shell_loop(void);
43 int show_key_export(char *home
);
46 #define SAMPLING_RATE 48000
47 #define FRAME_SIZE 256
51 static pthread_t ptid
;
53 static char *port
= "30111";
54 static char *stun_server
= "stunserver.org";
55 static char *alsadev
= "plughw:0,0";
57 extern sig_atomic_t quit
;
58 sig_atomic_t did_stun
= 0;
59 static sig_atomic_t incoming_call
= 0;
61 static struct pollfd
*pfds
= NULL
;
62 static struct alsa_dev
*dev
= NULL
;
63 static CELTEncoder
*encoder
= NULL
;
64 static CELTDecoder
*decoder
= NULL
;
65 static JitterBuffer
*jitter
= NULL
;
66 static SpeexEchoState
*echostate
= NULL
;
68 static void check_file_or_die(char *home
, char *file
, int maybeempty
)
72 memset(path
, 0, sizeof(path
));
73 slprintf(path
, sizeof(path
), "%s/%s", home
, file
);
75 panic("No such file %s! Type --keygen to generate initial config!\n",
77 if (!S_ISREG(st
.st_mode
))
78 panic("%s is not a regular file!\n", path
);
79 if ((st
.st_mode
& ~S_IFREG
) != (S_IRUSR
| S_IWUSR
))
80 panic("You have set too many permissions on %s (%o)!\n",
82 if (maybeempty
== 0 && st
.st_size
== 0)
83 panic("%s is empty!\n", path
);
86 static void check_config_exists_or_die(char *home
)
89 panic("No home dir specified!\n");
90 check_file_or_die(home
, FILE_CONTACTS
, 1);
91 check_file_or_die(home
, FILE_SETTINGS
, 0);
92 check_file_or_die(home
, FILE_PRIVKEY
, 0);
93 check_file_or_die(home
, FILE_PUBKEY
, 0);
94 check_file_or_die(home
, FILE_USERNAME
, 0);
97 static char *fetch_home_dir(void)
99 char *home
= getenv("HOME");
101 panic("No HOME defined!\n");
105 static void write_username(char *home
)
108 char path
[PATH_MAX
], *eof
;
110 memset(path
, 0, sizeof(path
));
111 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_USERNAME
);
112 printf("Username: [%s] ", getenv("USER"));
114 memset(user
, 0, sizeof(user
));
115 eof
= fgets(user
, sizeof(user
), stdin
);
116 user
[sizeof(user
) - 1] = 0;
117 user
[strlen(user
) - 1] = 0; /* omit last \n */
118 if (strlen(user
) == 0)
119 strlcpy(user
, getenv("USER"), sizeof(user
));
120 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
122 panic("Cannot open your username file!\n");
123 ret
= write(fd
, user
, strlen(user
));
124 if (ret
!= strlen(user
))
125 panic("Could not write username!\n");
127 info("Username written to %s!\n", path
);
130 static void create_transsipdir(char *home
)
134 memset(path
, 0, sizeof(path
));
135 slprintf(path
, sizeof(path
), "%s/%s", home
, ".transsip/");
137 ret
= mkdir(path
, S_IRWXU
);
138 if (ret
< 0 && errno
!= EEXIST
)
139 panic("Cannot create transsip dir!\n");
140 info("transsip directory %s created!\n", path
);
141 /* We also create empty files for contacts and settings! */
142 memset(path
, 0, sizeof(path
));
143 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_CONTACTS
);
144 fd
= open(path
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
);
146 panic("Cannot open contacts file!\n");
148 info("Empty contacts file written to %s!\n", path
);
149 memset(path
, 0, sizeof(path
));
150 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_SETTINGS
);
151 fd
= open(path
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
);
153 panic("Cannot open settings file!\n");
155 info("Empty settings file written to %s!\n", path
);
158 static void create_keypair(char *home
)
162 unsigned char publickey
[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
] = { 0 };
163 unsigned char secretkey
[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES
] = { 0 };
165 const char * errstr
= NULL
;
167 info("Reading from %s (this may take a while) ...\n", ENTROPY_SOURCE
);
168 fd
= open_or_die(ENTROPY_SOURCE
, O_RDONLY
);
169 ret
= read_exact(fd
, secretkey
, sizeof(secretkey
), 0);
170 if (ret
!= sizeof(secretkey
)) {
172 errstr
= "Cannot read from "ENTROPY_SOURCE
"!\n";
176 crypto_scalarmult_curve25519_base(publickey
, secretkey
);
177 memset(path
, 0, sizeof(path
));
178 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_PUBKEY
);
179 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
182 errstr
= "Cannot open pubkey file!\n";
185 ret
= write(fd
, publickey
, sizeof(publickey
));
186 if (ret
!= sizeof(publickey
)) {
188 errstr
= "Cannot write public key!\n";
192 info("Public key written to %s!\n", path
);
193 memset(path
, 0, sizeof(path
));
194 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_PRIVKEY
);
195 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
198 errstr
= "Cannot open privkey file!\n";
201 ret
= write(fd
, secretkey
, sizeof(secretkey
));
202 if (ret
!= sizeof(secretkey
)) {
204 errstr
= "Cannot write private key!\n";
209 memset(publickey
, 0, sizeof(publickey
));
210 memset(secretkey
, 0, sizeof(secretkey
));
212 panic("%s: %s", errstr
, strerror(errno
));
214 info("Private key written to %s!\n", path
);
217 static void check_config_keypair_or_die(char *home
)
222 const char * errstr
= NULL
;
223 unsigned char publickey
[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
];
224 unsigned char publicres
[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
];
225 unsigned char secretkey
[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES
];
227 memset(path
, 0, sizeof(path
));
228 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_PRIVKEY
);
229 fd
= open(path
, O_RDONLY
);
232 errstr
= "Cannot open privkey file!\n";
235 ret
= read(fd
, secretkey
, sizeof(secretkey
));
236 if (ret
!= sizeof(secretkey
)) {
238 errstr
= "Cannot read private key!\n";
242 memset(path
, 0, sizeof(path
));
243 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_PUBKEY
);
244 fd
= open(path
, O_RDONLY
);
247 errstr
= "Cannot open pubkey file!\n";
250 ret
= read(fd
, publickey
, sizeof(publickey
));
251 if (ret
!= sizeof(publickey
)) {
253 errstr
= "Cannot read public key!\n";
256 crypto_scalarmult_curve25519_base(publicres
, secretkey
);
257 err
= crypto_verify_32(publicres
, publickey
);
260 errstr
= "WARNING: your keypair is corrupted!!! You need to "
261 "generate new keys!!!\n";
266 memset(publickey
, 0, sizeof(publickey
));
267 memset(publicres
, 0, sizeof(publicres
));
268 memset(secretkey
, 0, sizeof(secretkey
));
270 panic("%s: %s\n", errstr
, strerror(errno
));
273 static int keygen(char *home
)
275 create_transsipdir(home
);
276 write_username(home
);
277 create_keypair(home
);
278 check_config_keypair_or_die(home
);
279 printf("\nNow edit your .transsip/settings file before starting i.e.:\n");
280 printf(" port <your-transsip-port>\n");
281 printf(" stun stunserver.org\n");
282 printf(" alsa plughw:0,0\n");
286 static void do_call_duplex(void)
289 int ret
, recv_started
= 0;
292 while (likely(!quit
)) {
293 ret
= poll(pfds
, nfds
+ 1, -1);
295 panic("Poll returned with %d!\n", ret
);
297 /* Received packets */
298 if (pfds
[nfds
].revents
& POLLIN
) {
299 n
= recv(sd
, msg
, MAX_MSG
, 0);
300 int recv_timestamp
= ((int*) msg
)[0];
302 JitterBufferPacket packet
;
303 packet
.data
= msg
+ 4;
305 packet
.timestamp
= recv_timestamp
;
306 packet
.span
= FRAME_SIZE
;
309 jitter_buffer_put(jitter
, &packet
);
313 /* Ready to play a frame (playback) */
314 if (alsa_play_ready(dev
, pfds
, nfds
)) {
315 short pcm
[FRAME_SIZE
* CHANNELS
];
317 JitterBufferPacket packet
;
318 /* Get audio from the jitter buffer */
320 packet
.len
= MAX_MSG
;
321 jitter_buffer_tick(jitter
);
322 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
326 celt_decode(dec_state
, (const unsigned char *)
327 packet
.data
, packet
.len
, pcm
);
329 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
333 /* Playback the audio and reset the echo canceller
334 if we got an underrun */
336 if (alsa_write(dev
, pcm
, FRAME_SIZE
))
337 speex_echo_state_reset(echo_state
);
338 /* Put frame into playback buffer */
339 speex_echo_playback(echo_state
, pcm
);
342 /* Audio available from the soundcard (capture) */
343 if (alsa_cap_ready(dev
, pfds
, nfds
)) {
344 short pcm
[FRAME_SIZE
* CHANNELS
],
345 pcm2
[FRAME_SIZE
* CHANNELS
];
346 char outpacket
[MAX_MSG
];
348 alsa_read(dev
, pcm
, FRAME_SIZE
);
350 /* Perform echo cancellation */
351 speex_echo_capture(echo_state
, pcm
, pcm2
);
352 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
355 celt_encode(enc_state
, pcm
, NULL
, (unsigned char *)
356 (outpacket
+ 4), PACKETSIZE
);
358 /* Pseudo header: four null bytes and a 32-bit
360 ((int*)outpacket
)[0] = send_timestamp
;
361 send_timestamp
+= FRAME_SIZE
;
363 rc
= sendto(sd
, outpacket
, PACKETSIZE
+ 4, 0,
364 (struct sockaddr
*) &remote_addr
,
365 sizeof(remote_addr
));
367 panic("cannot send to socket");
373 void call_out(char *host
, char *port
)
376 /* wait for accept */
379 printf("Trying to call %s:%s ...\n", host
, port
);
383 void call_in(int take
)
385 /* lookup addrbook */
390 if (incoming_call
== 0) {
391 printf("No incoming call right now!\n");
395 printf("Trying to take incoming call ...\n");
399 static void *thread(void *null
)
401 int sock
= -1, ret
, mtu
, nfds
, tmp
;
402 struct addrinfo hints
, *ahead
, *ai
;
405 while (did_stun
== 0)
408 memset(&hints
, 0, sizeof(hints
));
409 hints
.ai_family
= PF_UNSPEC
;
410 hints
.ai_socktype
= SOCK_DGRAM
;
411 hints
.ai_protocol
= IPPROTO_UDP
;
412 hints
.ai_flags
= AI_PASSIVE
;
414 ret
= getaddrinfo(NULL
, port
, &hints
, &ahead
);
416 panic("Cannot get address info!\n");
418 for (ai
= ahead
; ai
!= NULL
&& sock
< 0; ai
= ai
->ai_next
) {
419 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
422 if (ai
->ai_family
== AF_INET6
) {
425 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
436 #endif /* IPV6_V6ONLY */
438 mtu
= IP_PMTUDISC_DONT
;
439 setsockopt(sock
, SOL_IP
, IP_MTU_DISCOVER
, &mtu
, sizeof(mtu
));
440 ret
= bind(sock
, ai
->ai_addr
, ai
->ai_addrlen
);
449 panic("Cannot open socket!\n");
451 dev
= alsa_open(alsadev
, SAMPLING_RATE
, CHANNELS
, FRAME_SIZE
);
453 panic("Cannot open ALSA device %s!\n", alsadev
);
455 mode
= celt_mode_create(SAMPLING_RATE
, FRAME_SIZE
, NULL
);
456 encoder
= celt_encoder_create(mode
, CHANNELS
, NULL
);
457 decoder
= celt_decoder_create(mode
, CHANNELS
, NULL
);
459 nfds
= alsa_nfds(dev
);
460 pfds
= xmalloc(sizeof(*pfds
) * (nfds
+ 1));
461 alsa_getfds(dev
, pfds
, nfds
);
462 pfds
[nfds
].fd
= sock
;
463 pfds
[nfds
].events
= POLLIN
;
465 jitter
= jitter_buffer_init(FRAME_SIZE
);
467 jitter_buffer_ctl(jitter
, JITTER_BUFFER_SET_MARGIN
, &tmp
);
469 echostate
= speex_echo_state_init(FRAME_SIZE
, 10 * FRAME_SIZE
);
471 speex_echo_ctl(echostate
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
473 while (likely(!quit
)) {
474 ret
= poll(&pfds
[nfds
], 1, -1);
476 panic("Poll returned with %d!\n", ret
);
477 if (pfds
[nfds
].revents
& POLLIN
) {
478 /* Check for Auth pkt, if yes, set current caller and notifiy cli */
479 /* cli user must call take, that triggers call_in() */
490 static void start_server(void)
492 int ret
= pthread_create(&ptid
, NULL
, thread
, NULL
);
494 panic("Cannot create server thread!\n");
497 static void stop_server(void)
499 /* pthread_join(ptid, NULL);*/
502 static void help(void)
504 printf("\ntranssip %s, peer-to-peer elliptic-curve-crypto-based "
505 "telephony network\n", VERSION_STRING
);
506 printf("http://www.transsip.org\n\n");
507 printf("Usage: transsip [options]\n");
508 printf("Options:\n");
509 printf(" -k|--keygen Generate public/private keypair\n");
510 printf(" -v|--version Show version\n");
511 printf(" -h|--help Guess what?!\n\n");
513 printf(" There is no default port specified, so that you are forced\n");
514 printf(" to select your own!\n");
516 printf("Secret ingredient: 7647-14-5\n");
518 printf("Please report bugs to <bugs@transsip.org>\n");
519 printf("Copyright (C) 2011 Daniel Borkmann <daniel@transsip.org>,\n");
520 printf("License: GNU GPL version 2\n");
521 printf("This is free software: you are free to change and redistribute it.\n");
522 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
526 static void version(void)
528 printf("\ntranssip %s, peer-to-peer elliptic-curve-crypto-based "
529 "telephony network\n", VERSION_STRING
);
530 printf("Build: %s\n", BUILD_STRING
);
531 printf("http://www.transsip.org\n\n");
532 printf("Please report bugs to <bugs@transsip.org>\n");
533 printf("Copyright (C) 2011 Daniel Borkmann <daniel@transsip.org>,\n");
534 printf("License: GNU GPL version 2\n");
535 printf("This is free software: you are free to change and redistribute it.\n");
536 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
540 int main(int argc
, char **argv
)
542 char *home
= fetch_home_dir();
543 if (getuid() != geteuid())
545 if (getenv("LD_PRELOAD"))
546 panic("transsip cannot be preloaded!\n");
547 if (ptrace(PTRACE_TRACEME
, 0, 1, 0) < 0)
548 panic("transsip cannot be ptraced!\n");
549 curve25519_selftest();
550 if (argc
== 2 && (!strncmp("-k", argv
[1], strlen("-k")) ||
551 !strncmp("--keygen", argv
[1], strlen("--keygen")))) {
553 show_key_export(home
);
556 if (argc
== 2 && (!strncmp("-v", argv
[1], strlen("-v")) ||
557 !strncmp("--version", argv
[1], strlen("--version"))))
559 if (argc
== 2 && (!strncmp("-h", argv
[1], strlen("-h")) ||
560 !strncmp("--help", argv
[1], strlen("--help"))))
562 check_config_exists_or_die(home
);
563 check_config_keypair_or_die(home
);
575 char *get_stun_server(void)
580 int show_key_export(char *home
)
584 char path
[PATH_MAX
], tmp
[64];
585 check_config_exists_or_die(home
);
586 check_config_keypair_or_die(home
);
587 printf("Your public peer information:\n ");
589 memset(path
, 0, sizeof(path
));
590 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_USERNAME
);
591 fd
= open_or_die(path
, O_RDONLY
);
592 while ((ret
= read(fd
, tmp
, sizeof(tmp
))) > 0) {
593 ret
= write(STDOUT_FILENO
, tmp
, ret
);
597 memset(path
, 0, sizeof(path
));
598 slprintf(path
, sizeof(path
), "%s/%s", home
, FILE_PUBKEY
);
599 fd
= open_or_die(path
, O_RDONLY
);
600 ret
= read(fd
, tmp
, sizeof(tmp
));
601 if (ret
!= crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
)
602 panic("Cannot read public key!\n");
603 for (i
= 0; i
< ret
; ++i
)
605 printf("%02x\n\n", (unsigned char) tmp
[i
]);
607 printf("%02x:", (unsigned char) tmp
[i
]);