Skip to content

Commit b9ab305

Browse files
committed
- always transfer L3 protocol number between sll.protocol and TUN/TAP protocol field
- fixed possible bugs if local/remote endianness is different - added a protocol version exchange to detect incompatible master/slave couples - added linktype exchange to choose between TUN mode and TAP mode - fixed C option parameter use - added some debugging printf()
1 parent ad6e6c8 commit b9ab305

File tree

1 file changed

+120
-25
lines changed

1 file changed

+120
-25
lines changed

etherpuppet.c

Lines changed: 120 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343

4444
#define VERSION "v0.2"
4545

46+
#define PROTOVERSION 0x13370103
47+
4648
#define MTU 1600
4749

4850
#define PERROR(x) do { perror(x); exit(1); } while (0)
@@ -148,6 +150,29 @@ struct sock_fprog the_filter = {
148150
the_BPF,
149151
};
150152

153+
int sane(unsigned char x)
154+
{
155+
return ((x >= 0x20) && (x < 0x80));
156+
}
157+
158+
int hexdump(void *buf, int len)
159+
{
160+
unsigned char *b = buf;
161+
int i,j;
162+
163+
for (i=0; i < (len+15)/16*16; i++) {
164+
if (i < len) printf("%02x ",b[i]); else printf(" ");
165+
if (i%8 == 7) printf(" ");
166+
if (i%16 == 15) {
167+
for (j=i-15; (j < i) && (j < len); j++)
168+
printf("%c", sane(b[j]) ? b[j] : '.');
169+
printf("\n");
170+
}
171+
}
172+
}
173+
174+
175+
151176
void usage()
152177
{
153178
fprintf(stderr, "Usage: etherpuppet {-s port|-c targetip:port} [-B|-S|-M <arg>] [-C] -i iface\n"
@@ -160,7 +185,8 @@ void usage()
160185
"-B : do not use any BPF. Etherpuppet may see its own traffic!\n"
161186
"-S : build BPF filter with SSH_CONNECTION environment variable\n"
162187
"-M src:sp,dst:dp : BPF filter manual configuration\n"
163-
"-C : don't copy real interface parameters to virtual interface\n");
188+
"-C : don't copy real interface parameters to virtual interface\n"
189+
"-d : increase debug level (can be used more than once" );
164190
exit(0);
165191
}
166192

@@ -189,8 +215,9 @@ int main(int argc, char *argv[])
189215
struct sockaddr_in sin, sin2;
190216
struct sockaddr_ll sll;
191217
struct ifreq ifr;
192-
int s, s2, sinlen, sin2len, port, PORT, l, ifidx, m, n;
218+
int s, s2, sinlen, sin2len, sll_len, port, PORT, l, ifidx, m, n, v;
193219
short int h;
220+
short sll_hatype;
194221
struct hostent *host;
195222

196223
struct sigaction sa;
@@ -208,6 +235,7 @@ int main(int argc, char *argv[])
208235

209236
int MASTER = 0, CONFIG = 1;
210237
int MODE = 0, DEBUG = 0;
238+
int PPP = 0;
211239

212240
int BPF = BPF_AUTO;
213241

@@ -217,7 +245,7 @@ int main(int argc, char *argv[])
217245
sigaddset(&sa.sa_mask, SIGINT);
218246
sa.sa_flags = SA_SIGINFO | SA_ONESHOT | SA_RESTART;
219247

220-
while ((c = getopt(argc, argv, "ms:c:i:I:hdBSMC:v")) != -1) {
248+
while ((c = getopt(argc, argv, "ms:c:i:I:hdBSMCv")) != -1) {
221249
switch (c) {
222250
case 'v':
223251
version();
@@ -289,6 +317,8 @@ int main(int argc, char *argv[])
289317
sin2.sin_addr = *(struct in_addr *)host->h_addr;
290318
printf("Connecting to %s:%i...\n", inet_ntoa(sin2.sin_addr.s_addr), ntohs(sin2.sin_port));
291319
if (connect(s, (struct sockaddr *)&sin2, sizeof(sin2)) == -1) PERROR("connect");
320+
v = PROTOVERSION;
321+
if (send(s, &v, sizeof(l), 0) == -1) PERROR("send PROTOVERSION");
292322
}
293323
else {
294324
printf("Waiting for connection on port %i...\n", PORT);
@@ -298,6 +328,17 @@ int main(int argc, char *argv[])
298328
if (s2 == -1) PERROR("accept");
299329
close(s);
300330
s = s2;
331+
if (recv(s, &v, sizeof(l), 0) == -1) PERROR("recv PROTOVERSION");
332+
if (v != PROTOVERSION)
333+
ERROR("Protocol version mismatch local=%08x (%i.%i) remote=%08x (%i.%i)\n",
334+
PROTOVERSION, (PROTOVERSION >> 8) & 0xff, PROTOVERSION & 0xff,
335+
v, (v>>8)&0xff, v&0xff);
336+
else
337+
printf("Protocol version ok. local=%08x (%i.%i) remote=%08x (%i.%i)\n",
338+
PROTOVERSION, (PROTOVERSION >> 8) & 0xff, PROTOVERSION & 0xff,
339+
v, (v>>8)&0xff, v&0xff);
340+
341+
301342
}
302343

303344
sinlen = sizeof(sin);
@@ -310,10 +351,29 @@ int main(int argc, char *argv[])
310351
/* Create virtual interface */
311352
if ( (s2 = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");
312353

354+
l = recv(s, &sll_hatype, sizeof(sll_hatype),0);
355+
if (l == -1) PERROR("recv linktype");
356+
sll_hatype = ntohs(sll_hatype);
357+
358+
switch (sll_hatype) {
359+
case 1:
360+
printf("Remote linktype is %i (Ethernet)\n", sll_hatype);
361+
break;
362+
case 512:
363+
printf("Remote linktype is %i (PPP)\n", sll_hatype);
364+
PPP = 1;
365+
break;
366+
default:
367+
printf("Remote linktype %i is unknown. Using Ethernet.\n", sll_hatype);
368+
}
369+
313370
memset(&ifr, 0, sizeof(ifr));
314-
ifr.ifr_flags = IFF_TAP;
371+
if (PPP)
372+
ifr.ifr_flags = IFF_TUN;
373+
else
374+
ifr.ifr_flags = IFF_TAP;
315375
strncpy(ifr.ifr_name, ifname_opt, IFNAMSIZ);
316-
if (ioctl(s2, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");
376+
if (ioctl(s2, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl TUNSETIFF");
317377
memset(ifname,0,IFNAMSIZ+1);
318378
strncpy(ifname, ifr.ifr_name, IFNAMSIZ);
319379

@@ -403,14 +463,25 @@ int main(int argc, char *argv[])
403463

404464

405465
strncpy(ifr.ifr_name, iface, IF_NAMESIZE);
406-
if (ioctl(s2, SIOCGIFINDEX, &ifr) == -1) PERROR("ioctl");
466+
if (ioctl(s2, SIOCGIFINDEX, &ifr) == -1) PERROR("ioctl SIOCGIFINDEX");
407467
ifidx = ifr.ifr_ifindex;
408468

409469
sll.sll_family = AF_PACKET;
410470
sll.sll_protocol = htons(ETH_P_ALL);
411471
sll.sll_ifindex = ifidx;
412472

413473
if (bind(s2, (struct sockaddr *)&sll, sizeof(sll)) == -1) PERROR("bind");
474+
475+
sll_len = sizeof(sll);
476+
if (getsockname(s2, (struct sockaddr *)&sll, &sll_len) == -1) PERROR("getsockname");
477+
printf("Sending remote linktype: %i\n", sll.sll_hatype);
478+
if (sll.sll_hatype == 512) {
479+
printf("PPP mode\n");
480+
PPP = 1;
481+
}
482+
483+
sll_hatype = htons(sll.sll_hatype);
484+
send(s, &sll_hatype, sizeof(sll_hatype),0);
414485
}
415486

416487

@@ -431,12 +502,13 @@ int main(int argc, char *argv[])
431502

432503

433504
/* Send interface parameters */
434-
cmd = CMD_CMD | CMD_IFREQ;
505+
cmd = htons(CMD_CMD | CMD_IFREQ);
435506
for(ireq = 0; ireq < sizeof(ifclone_get_ioctl)/sizeof(int); ireq++) {
436507
memset(&ifr, 0, sizeof(ifr));
437508
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
438509
req = ifclone_set_ioctl[ireq];
439-
ioctl(s, ifclone_get_ioctl[ireq], &ifr);
510+
if (ioctl(s, ifclone_get_ioctl[ireq], &ifr) == -1)
511+
PERROR2("ioctl get");
440512
send(s, &cmd, 2, 0);
441513
send(s, &req, 4, 0);
442514
if ((req != SIOCSIFHWADDR) && (req != SIOCSIFMTU))
@@ -454,12 +526,13 @@ int main(int argc, char *argv[])
454526
if (DEBUG) write(1,">", 1);
455527
l = 0; /* BEEUUURK! */
456528
while (l < 2) {
457-
if ((m = read(s, buf+l, 2-l)) == -1) PERROR2("read(1)");
529+
if ((m = read(s, buf+l, 2-l)) == -1) PERROR2("read length");
458530
if (m == 0) longjmp(env, JMP_PEERCLOSED);
459531
l += m;
460532
}
461-
n = *(short *)buf;
462-
if (DEBUG) printf("%i\n",n);
533+
n = ntohs(*(short *)buf);
534+
if (DEBUG >= 2) printf("Received a %i %s\n", n&0x7fff,
535+
n&0x8000 ? "command":"byte packet");
463536
if (n & CMD_CMD) { /* Command from the peer */
464537
switch (n & 0x7fff) {
465538
case CMD_IFREQ:
@@ -468,7 +541,7 @@ int main(int argc, char *argv[])
468541
if (CONFIG) {
469542
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
470543
if (ioctl(s, req, &ifr) == -1)
471-
PERROR2("ioctl");
544+
PERROR3("ioctl set");
472545
}
473546
printf("Configure request [%04x] %s\n",
474547
req, CONFIG ? "applied" : "ignored");
@@ -478,29 +551,51 @@ int main(int argc, char *argv[])
478551
}
479552
}
480553
else { /* data */
481-
if (n > MTU) n = MTU;
554+
if (n > MTU) {
555+
printf("WARNING: truncated packet (%i > %i) . This should not happen\n", n, MTU);
556+
n = MTU;
557+
}
482558
l = 0;
483559
while (l < n) {
484-
if ((m = read(s, buf+4+l, n-l)) == -1) PERROR2("read(2)");
560+
if ((m = read(s, buf+2+l, n-l)) == -1) PERROR2("read packet data");
485561
l += m;
486562
}
487-
if (MASTER)
488-
*(short *)buf = *(short *)(buf+16);
489-
if (write(s2, MASTER ? buf : buf+4, MASTER ? n+4 : n) == -1)
490-
PERROR3("write");
563+
if (DEBUG >= 5) hexdump(buf+2, l);
564+
if (MASTER) {
565+
if (DEBUG >= 3) printf("Protocol = %04x\n",ntohs(*(short *)(buf+2)));
566+
if (write(s2, buf , n+2) == -1)
567+
PERROR3("write");
568+
}
569+
else {
570+
bzero(&sll, sizeof(sll));
571+
sll.sll_family = AF_PACKET;
572+
sll.sll_protocol = *(short *)(buf+2); /* htons(ntohs()) = Id */
573+
if (DEBUG >= 3) printf("Protocol = %04x\n",ntohs(sll.sll_protocol));
574+
sll.sll_ifindex = ifidx;
575+
if (sendto(s2, buf+4, n+2, 0, (struct sockaddr *)&sll, sizeof(sll)) == -1) PERROR2("sendto");
576+
}
491577
}
492578
}
493579
if (FD_ISSET(s2, &readset)) {
494580
if (DEBUG) write(1,"<", 1);
495-
if ((l = read(s2, MASTER ? buf : buf+4, MTU)) == -1) {
496-
PERROR3("read(0)");
497-
continue;
581+
if (MASTER) {
582+
l = read(s2, buf, MTU);
583+
if (l == -1) PERROR3("read");
584+
l -= 2;
585+
}
586+
else {
587+
sll_len = sizeof(sll);
588+
l = recvfrom(s2, buf+4, MTU, 0, (struct sockaddr *)&sll, &sll_len);
589+
*(short *)(buf+2) = sll.sll_protocol; /* htons(ntohs()) = Id */
590+
if (DEBUG > 4) printf("Protocol = %04x\n", ntohs(sll.sll_protocol));
591+
if (l == -1) PERROR3("recvfrom");
592+
l += 2;
498593
}
499-
h = MASTER ? l-4 : l;
594+
*(short *)buf = htons(l);
500595

501-
if (DEBUG) printf("%i\n",h);
502-
if (send(s, (void *)&h, 2, 0) == -1) PERROR2("send(1)");
503-
if (send(s, buf+4, h, 0) == -1) PERROR2("send(2)");
596+
if (send(s, buf, l+2, 0) == -1) PERROR2("send");
597+
if (DEBUG >= 3) printf("Sending %i bytes:\n", l);
598+
if (DEBUG >= 5) hexdump(buf+2, l);
504599
}
505600
}
506601
case JMP_ERROR:

0 commit comments

Comments
 (0)