├── deploy ├── Makefile ├── rc.eapolproxy ├── README └── main.cxx /deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rsync --exclude eapolproxy -a ./ root@192.168.1.5:~/eapolproxy/ 4 | 5 | ssh root@192.168.1.5 < 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include /* Must precede if*.h */ 10 | #include 11 | #include 12 | 13 | // EAPOL encapsulation: http://www.vocal.com/secure-communication/eapol-extensible-authentication-protocol-over-lan/ 14 | // EAP: http://tools.ietf.org/html/rfc3748 15 | 16 | 17 | #define ETH_ALEN 6 /* Octets in one ethernet addr */ 18 | #define ETH_HLEN 14 /* Total octets in header. */ 19 | #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ 20 | #define ETH_DATA_LEN 1500 /* Max. octets in payload */ 21 | #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ 22 | 23 | #define ETH_P_EAP 0x888e 24 | 25 | unsigned char mac_nearest[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; 26 | 27 | // eth0 address (to gateway) 28 | unsigned char mac_external[ETH_ALEN] = { 0x20, 0x25, 0x64, 0x0B, 0xCF, 0x71 }; 29 | 30 | // eth2 address (to aterm) 31 | unsigned char mac_internal[ETH_ALEN] = { 0x00, 0x25, 0x4B, 0xFC, 0xAC, 0x2E }; 32 | 33 | // eth address of aterm 34 | unsigned char mac_aterm[ETH_ALEN] = { 0x10, 0x66, 0x82, 0x23, 0xB3, 0x29 }; 35 | 36 | struct ethhdr { 37 | unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ 38 | unsigned char h_source[ETH_ALEN]; /* source ether addr */ 39 | unsigned short h_proto; /* packet type ID field */ 40 | } __attribute__((packed)); 41 | 42 | struct ethframe 43 | { 44 | ethhdr hdr; 45 | u_char payload[ETH_DATA_LEN]; 46 | }; 47 | 48 | struct CaptureThread 49 | { 50 | const char * devname; 51 | pthread_t thread; 52 | pcap_t * handle; 53 | 54 | CaptureThread(const char * name) 55 | { 56 | this->devname = name; 57 | this->thread = NULL; 58 | this->handle = NULL; 59 | } 60 | 61 | void start() 62 | { 63 | pthread_create(&thread, NULL, CaptureThread::_thread_entry, (void *)this); 64 | } 65 | 66 | void join() 67 | { 68 | void *arg; 69 | 70 | pthread_join(thread, &arg); 71 | } 72 | 73 | static void * _thread_entry(void *arg) 74 | { 75 | CaptureThread * me = (CaptureThread *)arg; 76 | 77 | return me->thread_entry(); 78 | } 79 | 80 | void * thread_entry(); 81 | }; 82 | 83 | FILE * logfile = stderr; 84 | 85 | const char * internal_devname = "eth2"; 86 | const char * external_devname = "eth0"; 87 | 88 | CaptureThread internal(internal_devname); 89 | CaptureThread external(external_devname); 90 | 91 | 92 | void print_ethernet_header(const u_char *Buffer, int Size) 93 | { 94 | struct ethhdr *eth = (struct ethhdr *)Buffer; 95 | 96 | fprintf(logfile , "Ethernet Header\n"); 97 | fprintf(logfile , " |-Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , eth->h_dest[5] ); 98 | fprintf(logfile , " |-Source Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_source[0] , eth->h_source[1] , eth->h_source[2] , eth->h_source[3] , eth->h_source[4] , eth->h_source[5] ); 99 | fprintf(logfile , " |-Protocol : 0x%04x \n",(unsigned short)ntohs(eth->h_proto)); 100 | 101 | int lc = 0; 102 | 103 | char buf[16]; 104 | 105 | for(int i = 0; i < Size; i++) 106 | { 107 | if(lc == 0) 108 | fprintf(logfile, " 0x%08x: ", i); 109 | 110 | fprintf(logfile, "%02x", Buffer[i]); 111 | buf[lc] = Buffer[i]; 112 | lc += 1; 113 | 114 | if(lc == 16) 115 | { 116 | fprintf(logfile, " "); 117 | for(int j=0; j 32 ? buf[j] : '.'); 119 | 120 | fprintf(logfile, "\n"); 121 | lc = 0; 122 | } 123 | else 124 | { 125 | fprintf(logfile, " "); 126 | } 127 | } 128 | 129 | for(int j=0; j 32 ? buf[j] : '.'); 131 | fprintf(logfile, "\n"); 132 | } 133 | 134 | const char * eapcodestr(int code) 135 | { 136 | switch(code) 137 | { 138 | case 1: return "REQUEST"; 139 | case 2: return "RESPONSE"; 140 | case 3: return "SUCCESS"; 141 | case 4: return "FAILURE"; 142 | } 143 | 144 | return "UNKNOWN"; 145 | } 146 | 147 | const char * eaptypestr(int type) 148 | { 149 | switch(type) 150 | { 151 | case 1: return "IDENTITY"; 152 | case 2: return "NOTIFICATION"; 153 | case 3: return "NAK"; 154 | case 4: return "MD5-CHALLENGE"; 155 | } 156 | 157 | return ""; 158 | } 159 | 160 | void print_eapol(const u_char *Buffer, int Size) 161 | { 162 | Buffer += sizeof(ethhdr); 163 | 164 | u_char encver = Buffer[0]; 165 | u_char enctype = Buffer[1]; 166 | u_short enclen = (Buffer[2] << 8) | Buffer[3]; 167 | 168 | u_char code = Buffer[4]; 169 | u_char id = Buffer[5]; 170 | u_short len = (Buffer[6] << 8) | Buffer[7]; 171 | u_char type = Buffer[8]; 172 | 173 | fprintf(logfile, " EncVer:%d\n", encver); 174 | fprintf(logfile, " EncType:%d\n", enctype); 175 | fprintf(logfile, " EncLen:%d\n", enclen); 176 | fprintf(logfile, " Code:%d (%s)\n", code, eapcodestr(code)); 177 | fprintf(logfile, " Id:%d\n", id); 178 | fprintf(logfile, " Len:%d\n", len); 179 | fprintf(logfile, " Type:%d (%s)\n", type, eaptypestr(type)); 180 | } 181 | 182 | void print_packet(const u_char *Buffer, int Size) 183 | { 184 | print_ethernet_header(Buffer, Size); 185 | 186 | print_eapol(Buffer, Size); 187 | } 188 | 189 | 190 | void internal_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) 191 | { 192 | struct ethhdr *eth = (struct ethhdr *)packet; 193 | 194 | if(ntohs(eth->h_proto) != ETH_P_EAP) 195 | return; 196 | 197 | fprintf(logfile, "------------------------------------------------------------------------------------------------------------\n"); 198 | fprintf(logfile, "Received %d bytes from internal interface\n", header->len); 199 | 200 | print_packet(packet, header->len); 201 | 202 | // dest address should always be the pseudo 'nearest' looking thing. 203 | //assert( memcmp(ð->h_dest, mac_nearest, ETH_ALEN) == 0 ); 204 | //assert( memcmp(ð->h_source, mac_internal, ETH_ALEN) == 0 ); 205 | 206 | // send packet out on the other interface 207 | //memcpy(eth->h_source, mac_external, ETH_ALEN); 208 | //print_packet(packet, header->len); 209 | 210 | int r = pcap_inject(external.handle, packet, header->len); 211 | 212 | fprintf(logfile, "Forwarded %d bytes to external interface\n", r); 213 | fprintf(logfile, "\n"); 214 | } 215 | 216 | 217 | void external_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) 218 | { 219 | struct ethhdr *eth = (struct ethhdr *)packet; 220 | 221 | if(ntohs(eth->h_proto) != ETH_P_EAP) 222 | return; 223 | 224 | fprintf(logfile, "------------------------------------------------------------------------------------------------------------\n"); 225 | fprintf(logfile, "Received %d bytes from external interface\n", header->len); 226 | 227 | print_packet(packet, header->len); 228 | 229 | //assert( memcmp(ð->h_dest, mac_external, ETH_ALEN) == 0 ); 230 | 231 | // send packet out on the other interface 232 | //memcpy(eth->h_dest, mac_aterm, ETH_ALEN); 233 | //print_packet(packet, header->len); 234 | 235 | int r = pcap_inject(internal.handle, packet, header->len); 236 | 237 | fprintf(logfile, "Forwarded %d bytes to internal interface\n", r); 238 | fprintf(logfile, "\n"); 239 | } 240 | 241 | 242 | void * CaptureThread::thread_entry() 243 | { 244 | char errbuf[PCAP_ERRBUF_SIZE]; 245 | const char * eap_filter = "ether proto 0x888e"; 246 | struct bpf_program eap_program; 247 | 248 | handle = pcap_open_live(devname, BUFSIZ, true, 1000, errbuf); 249 | if (handle == NULL) 250 | { 251 | fprintf(stderr, "Couldn't open device %s: %s\n", devname, errbuf); 252 | exit(2); 253 | } 254 | 255 | if (pcap_compile(handle, &eap_program, eap_filter, 1, 0) == -1) 256 | { 257 | pcap_geterr(handle); 258 | fprintf(stderr, "Couldn't parse filter '%s': %s\n", eap_filter, errbuf); 259 | exit(2); 260 | } 261 | 262 | if (pcap_setfilter(handle, &eap_program) == -1) 263 | { 264 | pcap_geterr(handle); 265 | fprintf(stderr, "Couldn't install filter '%s': %s\n", eap_filter, errbuf); 266 | exit(2); 267 | } 268 | 269 | if(!strcmp(devname, internal_devname)) 270 | pcap_loop(handle, -1, internal_callback, NULL); 271 | else 272 | pcap_loop(handle, -1, external_callback, NULL); 273 | 274 | /* And close the session */ 275 | pcap_close(handle); 276 | 277 | return NULL; 278 | } 279 | 280 | int docrc(u_char * buf, int size) 281 | { 282 | uLong crc = crc32(0, NULL, 0); 283 | 284 | crc = crc32(crc, buf, size); 285 | 286 | buf[size+0] = crc & 0xff; 287 | buf[size+1] = (crc >> 8) & 0xff; 288 | buf[size+2] = (crc >> 16) & 0xff; 289 | buf[size+3] = (crc >> 24) & 0xff; 290 | 291 | return size + 4; 292 | } 293 | 294 | void send_identity(pcap_t * pcap) 295 | { 296 | ethframe f; 297 | 298 | memset(&f, 0, sizeof(f)); 299 | 300 | f.hdr.h_source[0] = 0x00; 301 | f.hdr.h_source[1] = 0x25; 302 | f.hdr.h_source[2] = 0x4b; 303 | f.hdr.h_source[3] = 0xfc; 304 | f.hdr.h_source[4] = 0xac; 305 | f.hdr.h_source[5] = 0x2e; 306 | 307 | f.hdr.h_dest[0] = 0x10; 308 | f.hdr.h_dest[1] = 0x66; 309 | f.hdr.h_dest[2] = 0x82; 310 | f.hdr.h_dest[3] = 0x23; 311 | f.hdr.h_dest[4] = 0xb3; 312 | f.hdr.h_dest[5] = 0x29; 313 | 314 | f.hdr.h_proto = htons(ETH_P_EAP); 315 | 316 | f.payload[0] = 0x01; // eapol: version 317 | f.payload[1] = 0x00; // eapol: packet type 318 | f.payload[2] = 0x00; // eapol: length 319 | f.payload[3] = 0x05; // eapol: length 320 | 321 | int pktid = 5; 322 | 323 | f.payload[4] = 0x01; // EAP: request 324 | f.payload[5] = pktid; // EAP: id 325 | f.payload[6] = 0x00; // EAP: length 326 | f.payload[7] = 0x05; // EAP: length 327 | f.payload[8] = 0x01; // EAP: MD5 challenge 328 | f.payload[9] = 0x00; // EAP: MD5 size 329 | f.payload[10] = 0x00; // EAP: MD5 size 330 | f.payload[11] = 0x00; // EAP: MD5 size 331 | f.payload[12] = 0x00; // EAP: MD5 size 332 | 333 | int n = sizeof(ethhdr) + 13; 334 | 335 | print_packet((u_char *)&f, n); 336 | 337 | int r = pcap_inject(pcap, &f, n); 338 | printf("sent %d bytes\n", r); 339 | } 340 | 341 | 342 | void send_challenge(pcap_t * pcap) 343 | { 344 | ethframe f; 345 | 346 | memset(&f, 0, sizeof(f)); 347 | 348 | f.hdr.h_source[0] = 0x00; 349 | f.hdr.h_source[1] = 0x25; 350 | f.hdr.h_source[2] = 0x4b; 351 | f.hdr.h_source[3] = 0xfc; 352 | f.hdr.h_source[4] = 0xac; 353 | f.hdr.h_source[5] = 0x2e; 354 | 355 | f.hdr.h_dest[0] = 0x10; 356 | f.hdr.h_dest[1] = 0x66; 357 | f.hdr.h_dest[2] = 0x82; 358 | f.hdr.h_dest[3] = 0x23; 359 | f.hdr.h_dest[4] = 0xb3; 360 | f.hdr.h_dest[5] = 0x29; 361 | 362 | f.hdr.h_proto = htons(ETH_P_EAP); 363 | 364 | f.payload[0] = 0x01; // eapol: version 365 | f.payload[1] = 0x00; // eapol: packet type 366 | f.payload[2] = 0x00; // eapol: length 367 | f.payload[3] = 0x16; // eapol: length 368 | 369 | int pktid = 5; 370 | 371 | f.payload[4] = 0x01; // EAP: request 372 | f.payload[5] = pktid; // EAP: id 373 | f.payload[6] = 0x00; // EAP: length 374 | f.payload[7] = 0x16; // EAP: length 375 | f.payload[8] = 0x04; // EAP: MD5 challenge 376 | f.payload[9] = 0x10; // EAP: MD5 size 377 | 378 | 379 | 380 | int n = sizeof(ethhdr) + 10 + 16; 381 | 382 | //n = docrc((u_char *)&f, n); 383 | 384 | print_packet((u_char *)&f, n); 385 | 386 | int r = pcap_inject(pcap, &f, n); 387 | printf("sent %d bytes\n", r); 388 | } 389 | 390 | 391 | int main(int argc, const char **argv) 392 | { 393 | fprintf(logfile, "eapolproxy starting %s\n", __DATE__); 394 | 395 | fprintf(logfile, "starting %s\n", internal_devname); 396 | internal.start(); 397 | while(internal.handle == NULL) 398 | usleep(100000); 399 | 400 | fprintf(logfile, "starting %s\n", external_devname); 401 | external.start(); 402 | 403 | while(external.handle == NULL) 404 | usleep(100000); 405 | 406 | fprintf(logfile, "ready\n"); 407 | 408 | //send_identity(internal.handle); 409 | //sleep(1); 410 | //send_challenge(internal.handle); 411 | 412 | internal.join(); 413 | external.join(); 414 | 415 | return 1; 416 | } 417 | 418 | --------------------------------------------------------------------------------