📄 openvpn.c
字号:
tun_read_bytes += buf.len; /* Check the status return from read() */ check_status (buf.len, "read from tun"); if (buf.len > 0) {#if 0 /* special BSD <-> Linux mode, remove leading AF_INET from tun driver IP encoding */ if (options->tun_af_inet) tun_rm_head (&buf, AF_INET);#endif#ifdef USE_LZO /* Compress the packet. */ if (options->comp_lzo) lzo_compress (&buf, lzo_compress_buf, &lzo_compwork, &frame, 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 0 if (options->tun_af_inet) tun_add_head (&to_tun, AF_INET);#endif if (to_tun.len <= MAX_RW_SIZE_TUN(&frame)) { /* * Write to tun/tap device. */ const int size = write_tun (tuntap, BPTR (&to_tun), BLEN (&to_tun)); if (size > 0) tun_write_bytes += size; check_status (size, "write to tun"); /* 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) { /* * Setup for call to sendto() which will send * packet to remote over the UDP port. */ int size; ASSERT (addr_defined (&to_udp_addr)); /* In gremlin-test mode, we may choose to drop this packet */ if (!options->gremlin || ask_gremlin()) { /* * Let the traffic shaper know how many bytes * we wrote. */ if (options->shaper) shaper_wrote_bytes (&shaper, BLEN (&to_udp)); /* * Let the pinger know that we sent a packet. */ if (options->ping_send_timeout) event_timeout_reset (&ping_send_interval, current); /* Send packet */ size = sendto (udp_socket.sd, BPTR (&to_udp), BLEN (&to_udp), 0, (struct sockaddr *) &to_udp_addr, (socklen_t) sizeof (to_udp_addr)); if (size > 0) udp_write_bytes += size; } else size = 0; /* Check sendto() return status */ check_status (size, "write to UDP"); if (size > 0) { /* Did we write a different size packet than we intended? */ if (size != BLEN (&to_udp)) msg (D_LINK_ERRORS, "UDP packet was fragmented on write to %s (tried=%d,actual=%d)", print_sockaddr (&to_udp_addr), BLEN (&to_udp), size); } /* Log packet send */ msg (D_PACKET_CONTENT, "UDP WRITE to %s: %s", print_sockaddr (&to_udp_addr), PROTO_DUMP (&to_udp)); } else { msg (D_LINK_ERRORS, "UDP packet too large on write to %s (tried=%d,max=%d)", print_sockaddr (&to_udp_addr), to_udp.len, max_rw_size_udp); } /* * The free_to_udp flag means that we should free the packet buffer * after send. This flag is usually set when the TLS background * thread generated the packet buffer. */ if (free_to_udp) { free_to_udp = false; free_buf (&to_udp); } to_udp = nullbuf; } } } /* * Do Cleanup */ if (free_to_udp) free_buf (&to_udp); #if defined(USE_CRYPTO) && defined(USE_SSL) && defined(USE_PTHREAD) if (tls_multi) tls_thread_close (tls_thread_socket);#endif free_buf (&read_udp_buf); free_buf (&read_tun_buf);#ifdef USE_LZO if (options->comp_lzo) { lzo_compress_uninit (&lzo_compwork); free_buf (&lzo_compress_buf); free_buf (&lzo_decompress_buf); }#endif#ifdef USE_CRYPTO free_buf (&encrypt_buf); free_buf (&decrypt_buf);#ifdef USE_SSL if (tls_multi) tls_multi_free (tls_multi, true); if (data_channel_options) free (data_channel_options);#endif#endif /* USE_CRYPTO */ /* * Free key schedules */ if ( !(signal_received == SIGUSR1 && options->persist_key) ) key_schedule_free (ks); /* * Close UDP connection */ udp_socket_close (&udp_socket); if ( !(signal_received == SIGUSR1 && options->persist_remote_ip) ) { CLEAR (udp_socket_addr->remote); CLEAR (udp_socket_addr->actual); } if ( !(signal_received == SIGUSR1 && options->persist_local_ip) ) CLEAR (udp_socket_addr->local); /* * Close tun/tap device */ if ( !(signal_received == SIGUSR1 && options->persist_tun) ) { char* tuntap_actual = (char *) gc_malloc (sizeof (tuntap->actual)); strcpy (tuntap_actual, tuntap->actual); msg (M_INFO, "Closing tun/tap device"); close_tun (tuntap); /* Run the down script -- note that it will run at reduced privilege if, for example, "--user nobody" was used. */ run_script (options->down_script, tuntap_actual, MAX_RW_SIZE_TUN (&frame), max_rw_size_udp, options->ifconfig_local, options->ifconfig_remote); } done: /* pop our garbage collection level */ gc_free_level (gc_level); /* return the signal that brought us here */ { int s = signal_received; signal_received = 0; return s; }}intmain (int argc, char *argv[]){ const int gc_level = gc_new_level (); bool first_time = true; int sig;#ifdef PID_TEST packet_id_interactive_test(); /* test the sequence number code */ goto exit;#endif error_reset (); /* initialize error.c */ do { struct options options; init_options (&options); /* * Parse command line options, * and read configuration file. */ parse_argv (&options, argc, argv); /* * OpenSSL info print mode? */#ifdef USE_CRYPTO if (options.show_ciphers || options.show_digests#ifdef USE_SSL || options.show_tls_ciphers#endif ) { if (first_time) init_ssl_lib (); if (options.show_ciphers) show_available_ciphers (); if (options.show_digests) show_available_digests ();#ifdef USE_SSL if (options.show_tls_ciphers) show_available_tls_ciphers ();#endif free_ssl_lib (); goto exit; } /* * Possibly set --dev based on --dev-node. * For example, if --dev-node /tmp/foo/tun, and --dev undefined, * set --dev to tun. */ if (!options.dev) options.dev = dev_component_in_dev_node (options.dev_node); /* * Static pre-shared key generation mode? */ if (options.genkey) { struct key key; notnull (options.shared_secret_file, "shared secret output file (--secret)"); if (options.mlock) /* should we disable paging? */ do_mlockall(true); generate_key_random (&key, NULL); write_key_file (&key, options.shared_secret_file); CLEAR (key); goto exit; }#endif /* USE_CRYPTO */ /* * Persistent tun/tap device management mode? */#ifdef TUNSETPERSIST if (options.persist_config) { /* sanity check on options for --mktun or --rmtun */ notnull (options.dev, "tun/tap device (--dev)"); if (options.remote || options.ifconfig_local || options.ifconfig_remote#ifdef USE_CRYPTO || options.shared_secret_file#ifdef USE_SSL || options.tls_server || options.tls_client#endif#endif ) msg (M_FATAL, "Options error: options --mktun or --rmtun should only be used together with --dev"); tuncfg (options.dev, options.dev_type, options.dev_node, options.tun_ipv6, options.persist_mode); goto exit; }#endif /* * Main OpenVPN block -- tunnel generation mode */ {#ifdef USE_CRYPTO if (options.test_crypto) { notnull (options.shared_secret_file, "key file (--secret)"); } else#endif notnull (options.dev, "tun/tap device (--dev)"); /* * Sanity check on daemon/inetd modes */ if (options.daemon && options.inetd) { msg (M_WARN, "Options error: only one of --daemon or --inetd may be specified"); usage_small (); } if (options.inetd && (options.local || options.remote)) { msg (M_WARN, "Options error: --local or --remote cannot be used with --inetd"); usage_small (); } /* * Sanity check on MTU parameters */ if (options.tun_mtu_defined && options.udp_mtu_defined) { msg (M_WARN, "Options error: only one of --tun-mtu or --udp-mtu may be defined (note that --ifconfig implies --udp-mtu %d)", DEFAULT_UDP_MTU); usage_small (); } if (!options.tun_mtu_defined && !options.udp_mtu_defined) options.tun_mtu_defined = true; /* * Sanity check on --local, --remote, and ifconfig */ if (string_defined_equal (options.local, options.remote) && options.local_port == options.remote_port) { msg (M_WARN, "Options error: --remote and --local addresses are the same"); usage_small (); } if (string_defined_equal (options.local, options.ifconfig_local) || string_defined_equal (options.local, options.ifconfig_remote) || string_defined_equal (options.remote, options.ifconfig_local) || string_defined_equal (options.remote, options.ifconfig_remote)) { msg (M_WARN, "Options error: --local and --remote addresses must be distinct from --ifconfig addresses"); usage_small (); } if (string_defined_equal (options.ifconfig_local, options.ifconfig_remote)) { msg (M_WARN, "Options error: local and remote --ifconfig addresses must be different"); usage_small (); }#ifdef USE_CRYPTO if (first_time) init_ssl_lib ();#ifdef USE_SSL if (options.tls_server + options.tls_client + (options.shared_secret_file != NULL) > 1) { msg (M_WARN, "specify only one of --tls-server, --tls-client, or --secret"); usage_small (); } if (options.tls_server) { notnull (options.dh_file, "DH file (--dh)"); } if (options.tls_server || options.tls_client) { notnull (options.ca_file, "CA file (--ca)"); notnull (options.cert_file, "certificate file (--cert)"); notnull (options.priv_key_file, "private key file (--key)"); if (first_time && options.askpass) pem_password_callback (NULL, 0, 0, NULL); } else { /* * Make sure user doesn't specify any TLS options * when in non-TLS mode. */#define MUST_BE_UNDEF(parm) if (options.parm != def.parm) msg (M_FATAL, err, #parm); const char err[] = "Parameter %s can only be specified in TLS-mode, i.e. where --tls-server or --tls-client is also specified."; struct options def; init_options (&def); MUST_BE_UNDEF (ca_file); MUST_BE_UNDEF (dh_file); MUST_BE_UNDEF (cert_file); MUST_BE_UNDEF (priv_key_file); MUST_BE_UNDEF (cipher_list); MUST_BE_UNDEF (tls_verify); MUST_BE_UNDEF (tls_timeout); MUST_BE_UNDEF (renegotiate_bytes); MUST_BE_UNDEF (renegotiate_packets); MUST_BE_UNDEF (renegotiate_seconds); MUST_BE_UNDEF (handshake_window); MUST_BE_UNDEF (transition_window); MUST_BE_UNDEF (tls_auth_file); MUST_BE_UNDEF (single_session); MUST_BE_UNDEF (disable_occ); }#undef MUST_BE_UNDEF#endif /* USE_CRYPTO */#endif /* USE_SSL */ set_check_status (D_LINK_ERRORS, D_READ_WRITE); set_debug_level (options.verbosity); set_mute_cutoff (options.mute); /* Become a daemon if requested */ if (first_time) { if (options.daemon) { ASSERT (!options.inetd); become_daemon (options.cd_dir); } } /* show all option settings */ show_settings (&options); /* Do Work */ { struct udp_socket_addr usa; struct key_schedule ks; struct tuntap tuntap; CLEAR (usa); CLEAR (ks); clear_tuntap (&tuntap); do { sig = openvpn (&options, &usa, &tuntap, &ks, first_time); first_time = false; } while (sig == SIGUSR1); } } gc_collect (gc_level); } while (sig == SIGHUP); thread_cleanup();#ifdef USE_CRYPTO free_ssl_lib ();#endif exit: /* pop our garbage collection level */ gc_free_level (gc_level); return 0;}/* * Basic threading test. */#if defined(USE_PTHREAD) && defined(USE_CRYPTO)static void*test_crypto_thread (void *arg){ struct udp_socket_addr usa; struct tuntap tuntap; struct key_schedule ks; const struct options *opt = (struct options*) arg; set_nice (opt->nice_work); CLEAR (usa); CLEAR (ks); clear_tuntap (&tuntap); openvpn (opt, &usa, &tuntap, &ks, false); return NULL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -