├── Makefile ├── README.md ├── desockmulti.c ├── logging.c └── logging.h /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | 4 | ALL_MODULES=$(filter-out logging.c, $(patsubst %.c,%.so,$(wildcard *.c))) 5 | 6 | all: $(ALL_MODULES) 7 | 8 | COMMON_DEPS=logging.c 9 | desockmulti.so: CFLAGS+=-lpthread -lrt -ldl 10 | 11 | %.so: %.c $(COMMON_DEPS) 12 | $(CC) $^ -o $@ -shared -fPIC $(CFLAGS) 13 | 14 | clean: 15 | rm -f *.o 16 | rm -f *.so 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # desockmulti 2 | A de-socketing tool that is 10x faster than [desock (Preeny)](https://github.com/zardus/preeny) in fuzzing network protocols 3 | 4 | # Build 5 | `make` 6 | 7 | # Usage 8 | Similar to desock (Preeny): 9 | 10 | `USE_RAW_FORMAT=1 LD_PRELOAD=/path/to/desockmulti/desockmulti.so ./afl-fuzz -d -i testcase_dir -o findings_dir -- /path/to/program [...params...]` 11 | 12 | `USE_RAW_FORMAT=1` is telling desockmulti that the seed is in orginal format, but not the new multifuzz format (checking our MultiFuzz paper if you are interested, and the source code of MultiFuzz is here https://github.com/hdusoftsec/MultiFuzz). 13 | 14 | # Documentation 15 | Please check the Section 4.4 of our MultiFuzz paper, which can be downloaded from https://www.mdpi.com/1424-8220/20/18/5194/pdf . 16 | 17 | If you use desockmulti, please kindly help to cite our paper: 18 | 19 | Yingpei Zeng, Mingmin Lin, Shanqing Guo, Yanzhao Shen, Tingting Cui, Ting Wu, Qiuhua Zheng, Qiuhua Wang, MultiFuzz: A Coverage-Based Multiparty-Protocol Fuzzer for IoT Publish/Subscribe Protocols, Sensors, Vol.20, No.18, 5194, 2020. 20 | -------------------------------------------------------------------------------- /desockmulti.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Author: Yingpei Zeng 3 | * 4 | * If you use desockmulti, please help to cite our paper: 5 | Yingpei Zeng, Mingmin Lin, Shanqing Guo, Yanzhao Shen, Tingting Cui, Ting Wu, Qiuhua Zheng, Qiuhua Wang, MultiFuzz: A Coverage-Based Multiparty-Protocol Fuzzer for IoT Publish/Subscribe Protocols, Sensors, Vol.20, No.18, 5194, 2020. 6 | https://www.mdpi.com/1424-8220/20/18/5194/pdf 7 | 8 | */ 9 | 10 | #define _GNU_SOURCE 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "logging.h" 30 | 31 | // TODO: Enlarge MAX_SEED_SIZE using realloc or mmap 32 | 33 | #ifndef MIN 34 | # define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) 35 | # define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) 36 | #endif /* !MIN */ 37 | 38 | #define PREENY_MAX_FD 800 39 | #define PREENY_SOCKET_OFFSET 500 40 | #define READ_BUF_SIZE 65536 41 | 42 | #define MAX_SEED_SIZE READ_BUF_SIZE 43 | #define MAX_ACCEPT_SOCK 3 44 | #define MAX_CONNECT_SOCK MAX_ACCEPT_SOCK 45 | /* The max possible sock num in a seed */ 46 | #define MAX_SEED_SOCK_NUM (MAX_ACCEPT_SOCK+MAX_CONNECT_SOCK) 47 | /* The max packet number in a sock */ 48 | #define MAX_SEED_ONE_SOCK_PKT_NUM 10 49 | 50 | 51 | 52 | #define PREENY_SOCKET(x) (x+PREENY_SOCKET_OFFSET) 53 | 54 | int preeny_desock_shutdown_flag = 0; 55 | 56 | struct sock_packets 57 | { 58 | int num; 59 | char* packets[MAX_SEED_ONE_SOCK_PKT_NUM]; 60 | int lengths[MAX_SEED_ONE_SOCK_PKT_NUM]; 61 | }; 62 | 63 | char* socket_path_prefix = "unix.socket."; 64 | // Bool indicator 65 | int preeny_socket_hooked[PREENY_MAX_FD] = { 0 }; 66 | int preeny_socket_hooked_is_server[PREENY_MAX_FD] = { 0 }; 67 | pthread_t* preeny_socket_threads[PREENY_MAX_FD] = { 0 }; 68 | /* The needed accept number*/ 69 | int accept_num = 0; 70 | /* The already accepted number*/ 71 | int accept_done_num = 0; 72 | /* The needed connect number*/ 73 | int connect_num = 0; 74 | /* The already connected number*/ 75 | int connect_done_num = 0; 76 | // Next to allocated socket fd, starts from 0 77 | int next_alloc_index = 0; 78 | /* The number of sockets that opened in calling accept. It is not accurate since some request is dropped, 79 | use accept_sock_num instead */ 80 | //int open_content_socks_num=0; 81 | int accept_sock_num = 0; 82 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 83 | 84 | /* Random value for socket path, supporting multiple desockmulti instance */ 85 | int rand_value = 0; 86 | 87 | 88 | int socket_content_parsed = 0; 89 | struct sock_packets all_sock_contents[MAX_SEED_SOCK_NUM]; 90 | 91 | int exit_called = 0; 92 | 93 | 94 | struct client_para 95 | { 96 | int servfd; 97 | int self_index; 98 | }; 99 | 100 | timer_t timerid; 101 | int timer_cleared = 0; 102 | int timer_set = 0; 103 | void clean_timer() 104 | { 105 | if (!timer_cleared && timer_set) 106 | { 107 | timer_delete(timerid); 108 | timer_cleared = 1; 109 | } 110 | } 111 | 112 | //Thread function to be invoked when the periodic timer expires 113 | static int icount = 0; 114 | void thread_handler(union sigval val) 115 | { 116 | preeny_info("Handler entered with value : for %d times\n", ++icount); 117 | if (accept_num >0 && accept_done_num == 0) 118 | { 119 | preeny_info("No accept num, exit\n"); 120 | clean_timer(); 121 | exit(0); 122 | } 123 | } 124 | 125 | 126 | void setup_timer() 127 | { 128 | //https://riptutorial.com/posix/example/16306/posix-timer-with-sigev-thread-notification 129 | 130 | if (timer_set) { 131 | return; 132 | } 133 | 134 | struct sigevent sev; 135 | struct itimerspec trigger; 136 | 137 | /* Set all `sev` and `trigger` memory to 0 */ 138 | memset(&sev, 0, sizeof(struct sigevent)); 139 | memset(&trigger, 0, sizeof(struct itimerspec)); 140 | 141 | /* 142 | * Set the notification method as SIGEV_THREAD: 143 | * 144 | * Upon timer expiration, `sigev_notify_function` (thread_handler()), 145 | * will be invoked as if it were the start function of a new thread. 146 | * 147 | */ 148 | sev.sigev_notify = SIGEV_THREAD; 149 | sev.sigev_notify_function = &thread_handler; 150 | //sev.sigev_value.sival_ptr = &info; 151 | 152 | /* Create the timer. In this example, CLOCK_REALTIME is used as the 153 | * clock, meaning that we're using a system-wide real-time clock for 154 | * this timer. 155 | */ 156 | timer_create(CLOCK_REALTIME, &sev, &timerid); 157 | 158 | /* Timer expiration will occur withing 5 seconds after being armed 159 | * by timer_settime(). 160 | */ 161 | trigger.it_value.tv_sec = 0; 162 | trigger.it_value.tv_nsec = 20000000; 163 | 164 | /* Arm the timer. No flags are set and no old_value will be retrieved. 165 | */ 166 | timer_settime(timerid, 0, &trigger, NULL); 167 | 168 | 169 | timer_set = 1; 170 | } 171 | 172 | // 173 | // originals 174 | // 175 | int (*original_socket)(int, int, int); 176 | int (*original_bind)(int, const struct sockaddr*, socklen_t); 177 | int (*original_listen)(int, int); 178 | int (*original_accept)(int, struct sockaddr*, socklen_t*); 179 | int (*original_connect)(int sockfd, const struct sockaddr* addr, socklen_t addrlen); 180 | int (*original_close)(int fd); 181 | int (*original_shutdown)(int sockfd, int how); 182 | int (*original_setsockopt)(int sockfd, int level, int optname, 183 | const void* optval, socklen_t optlen); 184 | __attribute__((constructor)) void preeny_desock_orig() 185 | { 186 | original_socket = dlsym(RTLD_NEXT, "socket"); 187 | original_listen = dlsym(RTLD_NEXT, "listen"); 188 | original_accept = dlsym(RTLD_NEXT, "accept"); 189 | original_bind = dlsym(RTLD_NEXT, "bind"); 190 | original_connect = dlsym(RTLD_NEXT, "connect"); 191 | original_close = dlsym(RTLD_NEXT, "close"); 192 | original_shutdown = dlsym(RTLD_NEXT, "shutdown"); 193 | original_setsockopt = dlsym(RTLD_NEXT, "setsockopt"); 194 | 195 | srand(time(0)); 196 | rand_value = rand(); 197 | } 198 | 199 | 200 | void* preeny_connect_write(void* para) 201 | { 202 | struct client_para *parameter = (struct client_para*)para; 203 | int sockfd, newfd; 204 | int len; 205 | struct sockaddr_un serun; 206 | char buf[READ_BUF_SIZE]; 207 | char error_buf[1024]; 208 | 209 | preeny_info("preeny connect_write for serverfd=%d started\n", 210 | parameter->servfd); 211 | 212 | if ((sockfd = original_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 213 | perror("preeny client socket error"); 214 | clean_timer(); 215 | exit(0); 216 | } 217 | 218 | memset(&serun, 0, sizeof(serun)); 219 | serun.sun_family = AF_UNIX; 220 | #ifdef __linux__ 221 | serun.sun_path[0] = 0; 222 | sprintf(serun.sun_path+1, "%s%d.%d", socket_path_prefix, parameter->servfd, rand_value); 223 | len = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path+1) + 1; 224 | #else 225 | sprintf(serun.sun_path, "%s%d.%d", socket_path_prefix, parameter->servfd, rand_value); 226 | len = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); 227 | #endif // __linux__ 228 | 229 | if (original_connect(sockfd, (struct sockaddr*) & serun, len) < 0) { 230 | perror("preeny connect error"); 231 | clean_timer(); 232 | exit(0); 233 | } 234 | 235 | /* dup2 seems to be quite slow, and not calling dup2 to new sock fd like 236 | PREENY_SOCKET did improves the performance a lot. */ 237 | newfd = sockfd; 238 | 239 | preeny_info("preeny connect succeeds, write for serverfd=%d, client sock index=%d\n", 240 | parameter->servfd, parameter->self_index); 241 | 242 | if (all_sock_contents[parameter->self_index].num == 0) 243 | { 244 | goto end; 245 | } 246 | 247 | for (int i = 0; i < all_sock_contents[parameter->self_index].num && !preeny_desock_shutdown_flag; i++) 248 | { 249 | int readsize = MIN(READ_BUF_SIZE, all_sock_contents[parameter->self_index].lengths[i]); 250 | memcpy(buf, all_sock_contents[parameter->self_index].packets[i], readsize); 251 | //sprintf(buf, "test message from fd index %d\n", parameter->self_index); 252 | //int total_n = strlen(buf) + 1;// strlen(buf) + 1; 253 | int total_n = readsize; 254 | int n = 0; 255 | int r=0; 256 | while (n != total_n && !preeny_desock_shutdown_flag) 257 | { 258 | r = write(newfd, buf+r, total_n - n);// ; 259 | if (r < 0) 260 | { 261 | strerror_r(errno, error_buf, 1024); 262 | preeny_info("preeny write shutting down due to write error '%s'\n", error_buf); 263 | goto end; 264 | } 265 | n += r; 266 | } 267 | preeny_info("preeny write a %d bytes packet, client socket index = %d, client sockfd=%d\n", total_n, 268 | parameter->self_index, newfd); 269 | } 270 | 271 | end: 272 | original_shutdown(newfd, SHUT_WR); 273 | preeny_info("preeny connection for serverfd=%d client sockfd=%d shutdown\n", parameter->servfd, newfd); 274 | free(para); 275 | return NULL; 276 | 277 | } 278 | 279 | 280 | __attribute__((destructor)) void preeny_desock_shutdown() 281 | { 282 | int i,j; 283 | 284 | preeny_debug("shutting down desockmulti...\n"); 285 | preeny_desock_shutdown_flag = 1; 286 | 287 | 288 | for (i = 0; i < PREENY_MAX_FD; i++) 289 | { 290 | if (preeny_socket_threads[i]) 291 | { 292 | preeny_debug("sending SIGINT to thread %d...\n", i); 293 | pthread_join(*preeny_socket_threads[i], NULL); 294 | preeny_debug("... sent!\n"); 295 | } 296 | } 297 | 298 | for (i = 0; i < MAX_SEED_SOCK_NUM; i++) 299 | { 300 | for (j = 0; j < all_sock_contents[i].num; j++) 301 | { 302 | free(all_sock_contents[i].packets[j]); 303 | all_sock_contents[i].packets[j] = NULL; 304 | } 305 | all_sock_contents[i].num = 0; 306 | } 307 | 308 | preeny_debug("... shutdown complete!\n"); 309 | } 310 | 311 | 312 | 313 | /* Seed format is: accept_num(1byte)|connect_num(1byte)| {sock_index(1byte)|length(2bytes, little endian)|content}* 314 | */ 315 | void process_input_seed() 316 | { 317 | if (socket_content_parsed) { 318 | return; 319 | } 320 | int use_raw = 0; 321 | if (getenv("USE_RAW_FORMAT")) 322 | { 323 | use_raw = 1; 324 | } 325 | 326 | unsigned char buf[MAX_SEED_SIZE]; 327 | //int fd = open("crash1", O_RDONLY); 328 | //int read_num = read(fd, buf, MAX_SEED_SIZE); 329 | int read_num; 330 | if (use_raw) 331 | { 332 | // Leave 5 bytes for constructing a fake header before 333 | read_num = read(0, buf+5, MAX_SEED_SIZE-5); 334 | buf[0] = 0x01; 335 | buf[1] = 0x00; 336 | buf[2] = 0x00; 337 | buf[3] = 0xFF; 338 | buf[4] = 0xFF; 339 | read_num += 5; 340 | } 341 | else { 342 | read_num = read(0, buf, MAX_SEED_SIZE); 343 | } 344 | int pointer, sock_index, length, pkt_index; 345 | char* content; 346 | 347 | if (read_num <= 5) 348 | { 349 | preeny_info("Error, too small seed to be correct\n"); 350 | clean_timer(); 351 | exit(0); 352 | } 353 | 354 | memset(all_sock_contents, 0, sizeof(struct sock_packets) * MAX_SEED_SOCK_NUM); 355 | 356 | accept_num = buf[0]; 357 | accept_num = accept_num % (MAX_ACCEPT_SOCK+1); 358 | connect_num = buf[1]; 359 | connect_num = connect_num % (MAX_CONNECT_SOCK+1); 360 | int total = accept_num + connect_num; 361 | 362 | preeny_info("accept_num=%d, connect_num=%d\n", accept_num, connect_num); 363 | 364 | if (accept_num == 0) 365 | { 366 | clean_timer(); 367 | exit(0); 368 | } 369 | 370 | int has_packet = 0; 371 | int smallest_sock_index = -1; 372 | pointer = 2; 373 | while (pointer < read_num && pointer + 2 < read_num && !preeny_desock_shutdown_flag) 374 | { 375 | sock_index = buf[pointer++]; 376 | if (sock_index >= total && total > 0) // governor for robustness 377 | { 378 | sock_index = sock_index % total; 379 | } 380 | if (sock_index >= MAX_SEED_SOCK_NUM) 381 | { 382 | preeny_info("sock_index=%d is greater than threshold %d\n", sock_index, MAX_SEED_SOCK_NUM); 383 | break; 384 | } 385 | if (all_sock_contents[sock_index].num >= MAX_SEED_ONE_SOCK_PKT_NUM) 386 | { 387 | preeny_info("all_sock_contents[sock_index].num=%d is greater than threshold %d\n", 388 | all_sock_contents[sock_index].num, MAX_SEED_ONE_SOCK_PKT_NUM); 389 | break; 390 | } 391 | 392 | length = buf[pointer] + ( ((int)buf[pointer + 1]) << 8 ); 393 | pointer += 2; 394 | if (length > read_num - pointer) 395 | { 396 | length = read_num - pointer; 397 | } 398 | if (length <= 0) { 399 | break; 400 | } 401 | 402 | content = malloc(length); 403 | memcpy(content, &buf[pointer], length); 404 | preeny_info("Get pkt, sockindex=%d, length=%d, pkt[0]=%d\n", sock_index, length, buf[pointer]); 405 | pointer += length; 406 | 407 | pkt_index = all_sock_contents[sock_index].num; 408 | all_sock_contents[sock_index].num++; 409 | all_sock_contents[sock_index].lengths[pkt_index] = length; 410 | all_sock_contents[sock_index].packets[pkt_index] = content; 411 | 412 | has_packet = 1; 413 | if (sock_index > smallest_sock_index) { 414 | smallest_sock_index = sock_index; 415 | } 416 | } 417 | 418 | socket_content_parsed = 1; 419 | 420 | if (!has_packet) 421 | { 422 | preeny_info("No non-zero lenggth packet got, exit\n"); 423 | clean_timer(); 424 | exit(0); 425 | } 426 | 427 | if (smallest_sock_index >= accept_num) 428 | { 429 | preeny_info("No packets for accept sock, exit\n"); 430 | clean_timer(); 431 | exit(0); 432 | } 433 | } 434 | 435 | 436 | int socket(int domain, int type, int protocol) 437 | { 438 | 439 | int fd; 440 | 441 | if (domain != AF_INET && domain != AF_INET6) 442 | { 443 | preeny_info("Ignoring non-internet socket."); 444 | return original_socket(domain, type, protocol); 445 | } 446 | 447 | if (!socket_content_parsed) { 448 | pthread_mutex_lock(&mutex); 449 | process_input_seed(); 450 | pthread_mutex_unlock(&mutex); 451 | } 452 | 453 | setup_timer(); 454 | 455 | if ((fd = original_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 456 | perror("socket error"); 457 | clean_timer(); 458 | exit(1); 459 | } 460 | 461 | preeny_debug("Intercepted socket()! original type=%s fd=%d\n", domain == AF_INET ? "AF_INET" : "AF_INET6", fd); 462 | 463 | preeny_socket_hooked[fd] = 1; 464 | preeny_socket_hooked_is_server[fd] = 0; 465 | 466 | return fd; 467 | 468 | } 469 | 470 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 471 | { 472 | int newfd = original_accept(sockfd, addr, addrlen); 473 | if (preeny_socket_hooked[sockfd]) 474 | { 475 | preeny_socket_hooked_is_server[sockfd] = 1; 476 | if (newfd > 0) { 477 | preeny_socket_hooked[newfd] = 1; 478 | pthread_mutex_lock(&mutex); 479 | accept_sock_num++; 480 | pthread_mutex_unlock(&mutex); 481 | } 482 | preeny_info("Accept socket at serverfd=%d, got fd=%d, accept_sock_num=%d.\n", sockfd, newfd, accept_sock_num); 483 | } 484 | return newfd; 485 | } 486 | 487 | int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) 488 | { 489 | return accept(sockfd, addr, addrlen); 490 | } 491 | 492 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 493 | { 494 | struct sockaddr_un serun; 495 | int size; 496 | 497 | if (preeny_socket_hooked[sockfd]) 498 | { 499 | memset(&serun, 0, sizeof(serun)); 500 | serun.sun_family = AF_UNIX; 501 | #ifdef __linux__ 502 | serun.sun_path[0] = 0; 503 | sprintf(serun.sun_path+1, "%s%d.%d", socket_path_prefix, sockfd, rand_value); 504 | size = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path+1)+1; 505 | #else 506 | sprintf(serun.sun_path, "%s%d.%d", socket_path_prefix, sockfd, rand_value); 507 | size = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); 508 | unlink(serun.sun_path); 509 | #endif 510 | 511 | if (original_bind(sockfd, (struct sockaddr*) & serun, size) < 0) { 512 | perror("bind error"); 513 | preeny_info("sockfd=%d, size=%d, serun.sun_path=%s\n", sockfd, size, serun.sun_path+1); 514 | clean_timer(); 515 | exit(0); 516 | } 517 | preeny_info("preeny socket bound, Emulating bind on port %d\n", ntohs(((struct sockaddr_in*)addr)->sin_port)); 518 | return 0; 519 | } 520 | else 521 | { 522 | return original_bind(sockfd, addr, addrlen); 523 | } 524 | 525 | } 526 | 527 | int listen(int sockfd, int backlog) 528 | { 529 | int selected_fd_index = -1; 530 | int r; 531 | 532 | if (preeny_socket_hooked[sockfd]) 533 | { 534 | if (original_listen(sockfd, 20) < 0) { 535 | perror("listen error"); 536 | clean_timer(); 537 | exit(0); 538 | } 539 | preeny_info("preeny listen called, accepting connections ...\n"); 540 | 541 | int use_thread = 0; 542 | if (getenv("USE_THREAD_FORWARD")) 543 | { 544 | use_thread = 1; 545 | } 546 | 547 | while (1) 548 | { 549 | pthread_mutex_lock(&mutex); 550 | if (accept_done_num < accept_num) 551 | { 552 | selected_fd_index = next_alloc_index++; 553 | accept_done_num++; 554 | } 555 | else { 556 | pthread_mutex_unlock(&mutex); 557 | break; 558 | } 559 | pthread_mutex_unlock(&mutex); 560 | 561 | if (all_sock_contents[selected_fd_index].num == 0) 562 | { 563 | preeny_info("corresponding sock index %d has no packet, skip ...\n", selected_fd_index); 564 | } 565 | else { 566 | 567 | 568 | struct client_para* para = (struct client_para*) malloc(sizeof(struct client_para)); 569 | para->self_index = selected_fd_index; 570 | para->servfd = sockfd; 571 | 572 | if (use_thread) { 573 | /* Thread is slower, so do not use pthread to call preeny_connect_write but directly call the function 574 | if possible. */ 575 | preeny_socket_threads[selected_fd_index] = malloc(sizeof(pthread_t)); 576 | r = pthread_create(preeny_socket_threads[selected_fd_index], NULL, (void* (*)(void*))preeny_connect_write, 577 | (void*)para); 578 | } 579 | else { 580 | r = 0; preeny_connect_write((void*)para); 581 | } 582 | 583 | preeny_info("pthread_created or directly called for preeny_connect_write, accept_done_num %d, selected_fd_index %d \n", 584 | accept_done_num, selected_fd_index); 585 | if (r) 586 | { 587 | perror("failed creating back connect thread"); 588 | return -1; 589 | } 590 | } 591 | } 592 | return 0; 593 | 594 | } 595 | else return original_listen(sockfd, backlog); 596 | } 597 | 598 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 599 | { 600 | return original_connect(sockfd, addr, addrlen); 601 | } 602 | 603 | int close(int fd) { 604 | 605 | if (exit_called) { return 0; } 606 | if (fd == 198 || fd == 199) { return 0; } 607 | 608 | if (preeny_socket_hooked[fd]) 609 | { 610 | 611 | preeny_socket_hooked[fd] = 0; 612 | 613 | if (!preeny_socket_hooked_is_server[fd]) { 614 | 615 | int all_closed = 0; 616 | pthread_mutex_lock(&mutex); 617 | //open_content_socks_num--; 618 | accept_sock_num--; 619 | if (accept_sock_num == 0) { 620 | all_closed = 1; 621 | } 622 | preeny_info("preeny close called on fd %d, accept_sock_num =%d, all_closed=%d\n", 623 | fd, accept_sock_num, all_closed); 624 | pthread_mutex_unlock(&mutex); 625 | if (all_closed) { 626 | exit_called = 1; 627 | clean_timer(); 628 | exit(0); 629 | } 630 | } 631 | } 632 | 633 | return original_close(fd); 634 | } 635 | 636 | int shutdown(int sockfd, int how) { 637 | 638 | return original_shutdown(sockfd, how); 639 | } 640 | 641 | int setsockopt(int sockfd, int level, int optname, 642 | const void* optval, socklen_t optlen) 643 | { 644 | if (preeny_socket_hooked[sockfd]) 645 | { 646 | // Some option like SO_REUSEADDR will make the socket bind error (EINVAL), 647 | // so just ignore all options. 648 | return 0; 649 | } 650 | else 651 | { 652 | return original_setsockopt(sockfd, level, optname, 653 | optval, optlen); 654 | } 655 | 656 | } 657 | -------------------------------------------------------------------------------- /logging.c: -------------------------------------------------------------------------------- 1 | // This code is GPLed by Yan Shoshitaishvili 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include // zyp for logging time 10 | 11 | int preeny_debug_on = 1; 12 | int preeny_info_on = 1; 13 | int preeny_error_on = 1; 14 | 15 | 16 | struct timeval t; 17 | 18 | void preeny_debug(char *fmt, ...) 19 | { 20 | if (!preeny_debug_on) return; 21 | 22 | gettimeofday(&t, NULL); //zyp 23 | printf("+++ [%ld:%06ld] ", t.tv_sec, t.tv_usec); 24 | va_list args; 25 | va_start(args,fmt); 26 | vprintf(fmt,args); 27 | va_end(args); 28 | 29 | fflush(stdout); 30 | } 31 | 32 | void preeny_info(char *fmt, ...) 33 | { 34 | if (!preeny_info_on) return; 35 | 36 | gettimeofday(&t, NULL); //zyp 37 | printf("--- [%ld:%06ld] ", t.tv_sec, t.tv_usec); 38 | va_list args; 39 | va_start(args,fmt); 40 | vprintf(fmt,args); 41 | va_end(args); 42 | 43 | fflush(stdout); 44 | } 45 | 46 | void preeny_error(char *fmt, ...) 47 | { 48 | if (!preeny_error_on) return; 49 | 50 | fprintf(stderr, "!!! ERROR: "); 51 | va_list args; 52 | va_start(args,fmt); 53 | vfprintf(stderr, fmt,args); 54 | va_end(args); 55 | 56 | fflush(stderr); 57 | } 58 | 59 | __attribute__((constructor)) void preeny_logging_init() 60 | { 61 | preeny_debug_on = preeny_debug_on || (getenv("PREENY_DEBUG") && (strcmp(getenv("PREENY_DEBUG"), "1") == 0)); 62 | preeny_info_on = preeny_info_on || (getenv("PREENY_INFO") && (strcmp(getenv("PREENY_INFO"), "1") == 0)); 63 | preeny_error_on = preeny_error_on || (getenv("PREENY_ERROR") && (strcmp(getenv("PREENY_ERROR"), "1") == 0)); 64 | } 65 | -------------------------------------------------------------------------------- /logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern int preeny_debug_on; 4 | extern int preeny_info_on; 5 | extern int preeny_error_on; 6 | 7 | void preeny_debug(char *, ...); 8 | void preeny_info(char *, ...); 9 | void preeny_error(char *, ...); 10 | --------------------------------------------------------------------------------