int main(int argc, char **argv) { int status; int idx; int active_last = 0; int active = 0; struct redir_t *redir; int keep_going = 1; int reload_config = 0; uint8_t hwaddr[6]; struct ifreq ifr; int selfpipe; int fd = socket(AF_INET, SOCK_DGRAM, 0); options_init(); chilli_signals(&keep_going, &reload_config); process_options(argc, argv, 1); safe_strncpy(ifr.ifr_name, _options.dhcpif, sizeof(ifr.ifr_name)); #ifdef SIOCGIFHWADDR if (ioctl(fd, SIOCGIFHWADDR, (caddr_t)&ifr) == 0) { memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, PKT_ETH_ALEN); } else { log_err(errno, "could not get MAC address"); return -1; } #endif close(fd); /* create an instance of redir */ if (redir_new(&redir, &_options.uamlisten, _options.uamport, #ifdef ENABLE_UAMUIPORT _options.uamuiport #else 0 #endif )) { log_err(0, "Failed to create redir"); return -1; } if (redir_listen(redir)) { log_err(0, "Failed to create redir listen"); return -1; } redir_set(redir, hwaddr, (_options.debug)); redir_set_cb_getstate(redir, sock_redir_getstate); redir->cb_handle_url = redir_handle_url; if (net_select_init(&sctx)) log_err(errno, "select init"); selfpipe = selfpipe_init(); /* epoll */ net_select_addfd(&sctx, selfpipe, SELECT_READ); net_select_addfd(&sctx, redir->fd[0], SELECT_READ); net_select_addfd(&sctx, redir->fd[1], SELECT_READ); if (_options.gid && setgid(_options.gid)) { log_err(errno, "setgid(%d) failed while running with gid = %d\n", _options.gid, getgid()); } if (_options.uid && setuid(_options.uid)) { log_err(errno, "setuid(%d) failed while running with uid = %d\n", _options.uid, getuid()); } while (keep_going) { /* select/poll */ net_select_zero(&sctx); net_select_fd(&sctx, selfpipe, SELECT_READ); net_select_fd(&sctx, redir->fd[0], SELECT_READ); net_select_fd(&sctx, redir->fd[1], SELECT_READ); active = 0; if (reload_config) { reload_options(argc, argv); reload_config = 0; redir_set(redir, hwaddr, _options.debug); } for (idx=0; idx < max_requests; idx++) { conn_select_fd(&requests[idx].conn, &sctx); if (requests[idx].inuse && requests[idx].socket_fd) { time_t now = mainclock_tick(); int fd = requests[idx].socket_fd; int timeout = 60; if (now - requests[idx].last_active > timeout) { log_dbg("timeout connection %d", idx); redir_conn_finish(&requests[idx].conn, &requests[idx]); } else { int evt = SELECT_READ; timeout = 0; if (conn_write_remaining(&requests[idx].conn)) evt |= SELECT_WRITE; net_select_fd(&sctx, fd, evt); active++; } #if(_debug_ > 1) if (_options.debug) { struct sockaddr_in address; socklen_t addrlen = sizeof(address); if (getpeername(fd, (struct sockaddr *)&address, &addrlen) >= 0) { char line[512]; safe_snprintf(line, sizeof(line), "#%d (%d) %d connection from %s %d", timeout ? -1 : active, fd, (int) requests[idx].last_active, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); if (requests[idx].conn.sock) { addrlen = sizeof(address); if (getpeername(requests[idx].conn.sock, (struct sockaddr *)&address, &addrlen) >= 0) { safe_snprintf(line+strlen(line), sizeof(line)-strlen(line), " to %s %d", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); } } if (timeout) { safe_snprintf(line+strlen(line), sizeof(line)-strlen(line), " (timeout)"); } log_dbg("%s", line); } } #endif } } if (active != active_last) { log_dbg("active connections: %d", active); active_last = active; } status = net_select(&sctx); #if defined(USING_POLL) && defined(HAVE_SYS_EPOLL_H) && (_debug_ > 1) if (_options.debug && status > 0) { int i; log_dbg("epoll %d", status); for (i=0; i < status; i++) { log_dbg("epoll fd %d %d", sctx.events[i].data.fd, sctx.events[i].events); } } #endif switch (status) { case -1: log_err(errno, "select() returned -1!"); break; default: if (status > 0) { if (net_select_read_fd(&sctx, selfpipe)==1) { chilli_handle_signal(0, 0); } if (redir->fd[0]) if (net_select_read_fd(&sctx, redir->fd[0])==1 && redir_accept2(redir, 0) < 0) log_err(0, "redir_accept() failed!"); if (redir->fd[1]) if (net_select_read_fd(&sctx, redir->fd[1])==1 && redir_accept2(redir, 1) < 0) log_err(0, "redir_accept() failed!"); for (idx=0; idx < max_requests; idx++) { /* * Update remote connections with activity */ conn_select_update(&requests[idx].conn, &sctx); /* * Check client connections with activity */ if (requests[idx].inuse && requests[idx].socket_fd) { int fd = requests[idx].socket_fd; #ifdef HAVE_SSL if (requests[idx].sslcon) { if (openssl_check_accept(requests[idx].sslcon, 0) < 0) { log_dbg("ssl error %d", errno); redir_conn_finish(&requests[idx].conn, &requests[idx]); continue; } } #endif switch (net_select_write_fd(&sctx, fd)) { case 1: log_dbg("client writeable"); redir_cli_rewrite(&requests[idx], &requests[idx].conn); break; } switch (net_select_read_fd(&sctx, fd)) { case -1: log_dbg("EXCEPTION"); redir_conn_finish(&requests[idx].conn, &requests[idx]); break; case 1: { if (requests[idx].proxy) { char b[PKT_MAX_LEN]; int r; #ifdef HAVE_SSL if (requests[idx].sslcon) { /* log_dbg("proxy_read_ssl"); */ r = openssl_read(requests[idx].sslcon, b, sizeof(b)-1, 0); } else #endif r = safe_read(fd, b, sizeof(b)-1); /* log_dbg("proxy_read: %d %d", fd, r); */ if (r <= 0) { log_dbg("recv %d %d %d", r, requests[idx].conn.read_buf->slen - requests[idx].conn.read_pos, errno); if (!(r == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))) { if (redir_cli_rewrite(&requests[idx], &requests[idx].conn) == 0) { log_dbg("done reading and writing"); redir_conn_finish(&requests[idx].conn, &requests[idx]); } } } else if (r > 0) { int w; requests[idx].last_active = mainclock_tick(); w = net_write(requests[idx].conn.sock, b, r); /* log_dbg("proxy_write: %d", w); */ if (r != w) { log_err(errno, "problem writing what we read from client"); redir_conn_finish(&requests[idx].conn, &requests[idx]); } } } else { #ifdef HAVE_SSL go_again: #endif switch (redir_main(redir, fd, fd, &requests[idx].conn.peer, &requests[idx].baddr, requests[idx].uiidx, &requests[idx])) { case 1: /*log_dbg("redir cont'ed");*/ #ifdef HAVE_SSL if (requests[idx].sslcon && openssl_pending(requests[idx].sslcon) > 0) { log_dbg("ssl_pending, trying again"); goto go_again; } #endif break; case -1: log_dbg("redir error"); default: log_dbg("redir completed"); redir_conn_finish(&requests[idx].conn, &requests[idx]); break; } } } break; } } } } break; } } redir_free(redir); child_killall(SIGKILL); selfpipe_finish(); return 0; }
/* The following function deletes the value associated with a ** symbol. The symbol can be either a terminal or nonterminal. ** "yymajor" is the symbol code, and "yypminor" is a pointer to ** the value. */ static void yy_destructor( yyParser *yypParser, /* The parser */ YYCODETYPE yymajor, /* Type code for object to destroy */ YYMINORTYPE *yypminor /* The object to be destroyed */ ){ LineParserARG_FETCH; switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ /* TERMINAL Destructor */ case 1: /* REDIRECT_INPUT_FROM_FILE */ case 2: /* ARGUMENT */ case 3: /* REDIRECT_INPUT_FROM_FILE_DESCRIPTOR */ case 4: /* REDIRECT_OUTPUT_TO_FILE */ case 5: /* REDIRECT_OUTPUT_TO_FILE_DESCRIPTOR */ case 6: /* REDIRECT_OUTPUT_APPEND_TO_FILE */ case 7: /* PIPE */ case 8: /* OR */ case 9: /* AND */ case 10: /* BACKGROUND */ case 11: /* SEMICOLON */ { #line 24 "line_parser.y" free((yypminor->yy0)); #line 416 "line_parser.c" } break; case 13: /* redirection */ { #line 29 "line_parser.y" redir_free((yypminor->yy4)); #line 425 "line_parser.c" } break; case 14: /* command */ { #line 33 "line_parser.y" cmd_free((yypminor->yy2)); #line 434 "line_parser.c" } break; case 15: /* commandList */ { #line 37 "line_parser.y" cmd_list_free((yypminor->yy13)); #line 443 "line_parser.c" } break; case 16: /* start */ { #line 41 "line_parser.y" #line 450 "line_parser.c" } break; default: break; /* If no destructor action specified: do nothing */ } }