?? openvpn.c
字號:
ASSERT (buf_write (&buf, ping_string, sizeof (ping_string))); /* * We will treat the ping like any other outgoing packet, * encrypt, authenticate, etc. */#ifdef USE_LZO if (options->comp_lzo) lzo_compress (&buf, lzo_compress_buf, &lzo_compwork, &frame, current);#endif#ifdef FRAGMENT_ENABLE if (fragment) fragment_outgoing (fragment, &buf, &frame_fragment, current);#endif#ifdef USE_CRYPTO#ifdef USE_SSL mutex_lock (L_TLS); if (tls_multi) tls_pre_encrypt (tls_multi, &buf, &crypto_options);#endif openvpn_encrypt (&buf, encrypt_buf, &crypto_options, &frame, current);#endif udp_socket_get_outgoing_addr (&buf, &udp_socket, &to_udp_addr);#ifdef USE_CRYPTO#ifdef USE_SSL if (tls_multi) tls_post_encrypt (tls_multi, &buf); mutex_unlock (L_TLS);#endif#endif to_udp = buf; free_to_udp = false; msg (D_PACKET_CONTENT, "SENT PING"); } event_timeout_wakeup (&ping_send_interval, current, &timeval); tv = &timeval; } } /* do a quick garbage collect */ gc_collect (gc_level); /* * Set up for select call. * * Decide what kind of events we want to wait for. */ FD_ZERO (&reads); FD_ZERO (&writes); /* * If outgoing data (for UDP port) pending, wait for ready-to-send * status from UDP port. Otherwise, wait for incoming data on TUN/TAP device. */ if (to_udp.len > 0) { /* * If sending this packet would put us over our traffic shaping * quota, don't send -- instead compute the delay we must wait * until it will be OK to send the packet. */#ifdef HAVE_GETTIMEOFDAY int delay = 0; /* set traffic shaping delay in microseconds */ if (options->shaper) delay = max_int (delay, shaper_delay (&shaper)); if (delay >= 1000) { shaper_soonest_event (&timeval, delay); tv = &timeval; } else { FD_SET (udp_socket.sd, &writes); }#else /* HAVE_GETTIMEOFDAY */ FD_SET (udp_socket.sd, &writes);#endif /* HAVE_GETTIMEOFDAY */ }#ifdef FRAGMENT_ENABLE else if (!fragment || !fragment_outgoing_defined (fragment))#else else#endif { if (tuntap->fd >= 0) { FD_SET (tuntap->fd, &reads); }#if defined(USE_CRYPTO) && defined(USE_SSL) && defined(USE_PTHREAD) if (tls_multi) FD_SET (TLS_THREAD_SOCKET (&thread_parms), &reads);#endif } /* * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status * from device. Otherwise, wait for incoming data on UDP port. */ if (to_tun.len > 0) { if (tuntap->fd >= 0) FD_SET (tuntap->fd, &writes); } else { FD_SET (udp_socket.sd, &reads); } /* * Possible scenarios: * (1) udp port has data available to read * (2) udp port is ready to accept more data to write * (3) tun dev has data available to read * (4) tun dev is ready to accept more data to write * (5) tls background thread has data available to forward to udp port * (6) we received a signal (handler sets signal_received) * (7) timeout (tv) expired (from TLS, shaper, inactivity timeout, or ping timeout) */ /* * Wait for something to happen. */ if (!signal_received) { msg (D_SELECT, "SELECT %s|%s|%s|%s %d/%d", (tuntap->fd >= 0 && FD_ISSET (tuntap->fd, &reads)) ? "TR" : "tr", (tuntap->fd >= 0 && FD_ISSET (tuntap->fd, &writes)) ? "TW" : "tw", FD_ISSET (udp_socket.sd, &reads) ? "UR" : "ur", FD_ISSET (udp_socket.sd, &writes) ? "UW" : "uw", tv ? (int)tv->tv_sec : -1, tv ? (int)tv->tv_usec : -1 ); stat = select (fm, &reads, &writes, NULL, tv); check_status (stat, "select", NULL); } /* current should always be a reasonably up-to-date timestamp */ current = time (NULL);#ifdef HAVE_SIGNAL_H /* * Did we get a signal before or while we were waiting * in select() ? */ if (signal_received) { if (signal_received == SIGUSR2) { msg (M_INFO, "Current OpenVPN Statistics:"); msg (M_INFO, " TUN/TAP read bytes: " counter_format, tun_read_bytes); msg (M_INFO, " TUN/TAP write bytes: " counter_format, tun_write_bytes); msg (M_INFO, " UDP read bytes: " counter_format, udp_read_bytes); msg (M_INFO, " UDP write bytes: " counter_format, udp_write_bytes);#ifdef USE_LZO if (options->comp_lzo) lzo_print_stats (&lzo_compwork); #endif signal_received = 0; continue; } /* for all other signals (INT, TERM, HUP, USR1) we break */ switch (signal_received) { case SIGINT: msg (M_INFO, "SIGINT received, exiting"); break; case SIGTERM: msg (M_INFO, "SIGTERM received, exiting"); break; case SIGHUP: msg (M_INFO, "SIGHUP received, restarting"); break; case SIGUSR1: msg (M_INFO, "SIGUSR1 received, restarting"); break; default: msg (M_INFO, "Unknown signal %d received", signal_received); break; } break; }#endif /* HAVE_SIGNAL_H */ if (!stat) /* timeout? */ continue; if (stat > 0) { /* Incoming data on UDP port */ if (FD_ISSET (udp_socket.sd, &reads)) { /* * Set up for recvfrom call to read datagram * sent to our UDP port from any source address. */ struct sockaddr_in from; socklen_t fromlen = sizeof (from); ASSERT (!to_tun.len); buf = read_udp_buf; ASSERT (buf_init (&buf, EXTRA_FRAME (&frame))); ASSERT (buf_safe (&buf, max_rw_size_udp)); fromlen = sizeof (from); buf.len = recvfrom (udp_socket.sd, BPTR (&buf), max_rw_size_udp, 0, (struct sockaddr *) &from, &fromlen); ASSERT (fromlen == sizeof (from)); if (buf.len > 0) udp_read_bytes += buf.len; /* check recvfrom status */ check_status (buf.len, "read from UDP", &udp_socket); /* take action to corrupt packet if we are in gremlin test mode */ if (options->gremlin) { if (!ask_gremlin()) buf.len = 0; corrupt_gremlin(&buf); } /* log incoming packet */#ifdef LOG_RW if (check_debug_level (D_LOG_RW) && !check_debug_level (D_LOG_RW + 1)) fprintf (stderr, "R");#endif msg (D_UDP_RW, "UDP READ [%d] from %s: %s", BLEN (&buf), print_sockaddr (&from), PROTO_DUMP (&buf)); /* * Good, non-zero length packet received. * Commence multi-stage processing of packet, * such as authenticate, decrypt, decompress. * If any stage fails, it sets buf.len to 0, * telling downstream stages to ignore the packet. */ if (buf.len > 0) { udp_socket_incoming_addr (&buf, &udp_socket, &from);#ifdef USE_CRYPTO#ifdef USE_SSL mutex_lock (L_TLS); if (tls_multi) { /* * If tls_pre_decrypt returns true, it means the incoming * packet was a good TLS control channel packet. If so, TLS code * will deal with the packet and set buf.len to 0 so downstream * stages ignore it. * * If the packet is a data channel packet, tls_pre_decrypt * will load crypto_options with the correct encryption key * and return false. */ if (tls_pre_decrypt (tls_multi, &from, &buf, &crypto_options, current)) {#ifdef USE_PTHREAD /* tell TLS thread a packet is waiting */ if (tls_thread_process (&thread_parms) == -1) { msg (M_WARN, "TLS thread is not responding, exiting (1)"); signal_received = 0; mutex_unlock (L_TLS); break; }#else interval_action (&tmp_int, current);#endif /* USE_PTHREAD */ /* reset packet received timer if TLS packet */ if (options->ping_rec_timeout) event_timeout_reset (&ping_rec_interval, current); } }#endif /* USE_SSL */ /* authenticate and decrypt the incoming packet */ openvpn_decrypt (&buf, decrypt_buf, &crypto_options, &frame, current);#ifdef USE_SSL mutex_unlock (L_TLS);#endif /* USE_SSL */#endif /* USE_CRYPTO */#ifdef FRAGMENT_ENABLE if (fragment) fragment_incoming (fragment, &buf, &frame_fragment, current);#endif#ifdef USE_LZO /* decompress the incoming packet */ if (options->comp_lzo) lzo_decompress (&buf, lzo_decompress_buf, &lzo_compwork, &frame);#endif /* * Set our "official" outgoing address, since * if buf.len is non-zero, we know the packet * authenticated. In TLS mode we do nothing * because TLS mode takes care of source address * authentication. * * Also, update the persisted version of our packet-id. */ if (!TLS_MODE) udp_socket_set_outgoing_addr (&buf, &udp_socket, &from); /* reset packet received timer */ if (options->ping_rec_timeout && buf.len > 0) event_timeout_reset (&ping_rec_interval, current); /* Did we just receive an openvpn ping packet? */ if (buf_string_match (&buf, ping_string, sizeof (ping_string))) { msg (D_PACKET_CONTENT, "RECEIVED PING"); buf.len = 0; /* drop it */ } to_tun = buf; } else { to_tun = nullbuf; } }#if defined(USE_CRYPTO) && defined(USE_SSL) && defined(USE_PTHREAD) /* Incoming data from TLS background thread */ else if (tls_multi && FD_ISSET (TLS_THREAD_SOCKET (&thread_parms), &reads)) { int s; ASSERT (!to_udp.len); s = tls_thread_rec_buf (&thread_parms, &tt_ret, true); if (s == 1) { /* * TLS background thread has a control channel * packet to send to remote. */ to_udp = tt_ret.to_udp; to_udp_addr = tt_ret.to_udp_addr; /* tell UDP packet writer to free buffer after write */ free_to_udp = true; } /* remote died? */ else if (s == -1) { msg (M_WARN, "TLS thread is not responding, exiting (2)"); signal_received = 0; break; } }#endif /* Incoming data on TUN device */ else if (tuntap->fd >= 0 && FD_ISSET (tuntap->fd, &reads)) { /* * Setup for read() call on TUN/TAP device. */ ASSERT (!to_udp.len); buf = read_tun_buf; ASSERT (buf_init (&buf, EXTRA_FRAME (&frame))); ASSERT (buf_safe (&buf, MAX_RW_SIZE_TUN (&frame))); buf.len = read_tun (tuntap, BPTR (&buf), MAX_RW_SIZE_TUN (&frame)); if (buf.len > 0) tun_read_bytes += buf.len; /* Check the status return from read() */ check_status (buf.len, "read from TUN/TAP", NULL); /* show packet content */ msg (D_TUN_RW, "TUN READ [%d]: %s md5=%s", BLEN (&buf), format_hex (BPTR (&buf), BLEN (&buf), 80), MD5SUM (BPTR (&buf), BLEN (&buf)));#ifdef FRAGMENT_ENABLE /* if packet is too big, we might want to bounce back a "fragmentation needed but DF set ICMP message */ if (fragment) fragment_check_fragmentability (fragment, &frame_fragment, &buf);#endif if (buf.len > 0) {#if PASSTOS_CAPABILITY if (options->passtos) { /* Get the TOS before compression/encryption. */ iph = (struct iphdr*) BPTR (&buf); /* Check that it's an IPv4 packet. */ if (iph->version == 0x04) { ptos = iph->tos; ptos_defined = true; } }#endif#ifdef USE_LZO /* Compress the packet. */ if (options->comp_lzo) lzo_compress (&buf, lzo_compress_buf, &lzo_compwork, &frame, current);#endif#ifdef FRAGMENT_ENABLE if (fragment) fragment_outgoing (fragment, &buf, &frame_fragment, current);#endif#ifdef USE_CRYPTO#ifdef USE_SSL /* * If TLS mode, get the key we will use to encrypt * the packet. */ mutex_lock (L_TLS); if (tls_multi) tls_pre_encrypt (tls_multi, &buf, &crypto_options);#endif /* * Encrypt the packet and write an optional * HMAC authentication record. */ openvpn_encrypt (&buf, encrypt_buf, &crypto_options, &frame, current);#endif /* * Get the address we will be sending the packet to. */ udp_socket_get_outgoing_addr (&buf, &udp_socket, &to_udp_addr);#ifdef USE_CRYPTO#ifdef USE_SSL /* * In TLS mode, prepend the appropriate one-byte opcode * to the packet which identifies it as a data channel * packet and gives the low-permutation version of * the key-id to the recipient so it knows which * decrypt key to use. */ if (tls_multi) tls_post_encrypt (tls_multi, &buf); mutex_unlock (L_TLS);#endif#endif to_udp = buf; } else { to_udp = nullbuf; } free_to_udp = false; } /* TUN device ready to accept write */ else if (tuntap->fd >= 0 && FD_ISSET (tuntap->fd, &writes)) { /* * Set up for write() call to TUN/TAP * device. */ ASSERT (to_tun.len > 0); if (to_tun.len <= MAX_RW_SIZE_TUN(&frame)) { /* * Write to TUN/TAP device. */ int size; msg (D_TUN_RW, "TUN WRITE [%d]: %s md5=%s", BLEN (&to_tun), format_hex (BPTR (&to_tun), BLEN (&to_tun), 80), MD5SUM (BPTR (&to_tun), BLEN (&to_tun))); size = write_tun (tuntap, BPTR (&to_tun), BLEN (&to_tun)); if (size > 0) tun_write_bytes += size; check_status (size, "write to TUN/TAP", NULL); /* check written packet size */ if (size > 0) { /* Did we write a different size packet than we intended? */ if (size != BLEN (&to_tun)) msg (D_LINK_ERRORS, "TUN/TAP packet was fragmented on write to %s (tried=%d,actual=%d)", tuntap->actual, BLEN (&to_tun), size); } } else { /* * This should never happen, probably indicates some kind * of MTU mismatch. */ msg (D_LINK_ERRORS, "tun packet too large on write (tried=%d,max=%d)", to_tun.len, MAX_RW_SIZE_TUN (&frame)); } /* * Putting the --inactive timeout reset here, ensures that we will timeout * if the remote goes away, even if we are trying to send data to the * remote and failing. */ if (options->inactivity_timeout) event_timeout_reset (&inactivity_interval, current); to_tun = nullbuf; } /* UDP port ready to accept write */ else if (FD_ISSET (udp_socket.sd, &writes)) { if (to_udp.len > 0 && to_udp.len <= max_rw_size_udp) { /*
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -