Set source address for UDP packets from multihomed server
PATCH 1/1 Set source address for UDP packets from multihomed server
Hi.
This is the first of 4 patches that I would like to offer for openvpn.
They are against 2.0_beta7.
This first one is a refinement of a patch I posted earlier which, at that time, didn't work.
The purpose of the patch is to use the IP_PKTINFO socket option to get and set the local address for UDP packets being sent or received. This means that if you have a multihomed server, then packets sent to it will always come from the address that they corresponding packets were sent to. This is needed to pass cleanly through a NAT.
In replaces "struct sockaddr_in from" in "struct context_2" with
struct sockaddr_in incoming_from, incoming_to
and records the address provided by IP_PKTINFO in incoming_to.
It adds "struct sockaddr_in actuallocal" alongside "struct sockaddr_in actual" in "struct lock_socket_addr", for storing the local enpoint if a udp "connection" in this structure.
It adds "struct sockaddr_in local_addr" alongside "remote_addr" in "struct key_state" for a similar purpose.
And it makes sure these fields are set and used appropriately.
The main reason that it didn't work before was that in multi_process_incoming_link, when the packet and address are transferred from the "mt" structure into the per-session context structure, I wasn't copying the incoming_to address as well. I do now.
One part of the change that I am not completely happy with is
+ /* alway set localaddr address */
+ info->lsa->actuallocal = *localaddr;
in link_socket_set_outgoing_addr.
The current code only changes the outgoing address if it has changed, and it does that inside link_socket_connection_initiated. However it is possible for the localaddress to change without the remote address changing.
e.g. If I stop and restart my openvpn instance on my notebook, and it gets a different IP address via DNS lookup. In this case it will appear to be a continuation of the same session, but will need to use a different local address. I think it is OK to change the localaddress on every packet, but I am open to be convinced otherwise, or that the code could be cleaner.
Anyway, here is the patch. I hope it can be included in an upcoming beta of openvpn.
Thanks,
NeilBrown
============================================
### Diffstat output
./forward.c | 23 ++++++++++++-------- ./multi.c | 10 +++++--- ./openvpn.h | 5 +++- ./socket.c | 46 ++++++++++++++++++++++++++++++++++++++++- ./socket.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- ./ssl.c | 25 +++++++++++++++++----- ./ssl.h | 4 +++ 7 files changed, 148 insertions(+), 32 deletions(-)
forward.c renamed from forward.c~current~ +14 -9
@@ -87,6 +87,7 @@ check_tls_dowork (struct context *c) {if (tls_multi_process (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, + &c->c2.from_link_addr,get_link_socket_info (c), &wakeup)) {update_time ();
@@ -342,7 +343,7 @@ encrypt_sign (struct context *c, bool co* Get the address we will be sending the packet to. */ link_socket_get_outgoing_addr (&c->c2.buf,get_link_socket_info (c), - &c->c2.to_link_addr); + &c->c2.to_link_addr, &c->c2.from_link_addr);#ifdef USE_CRYPTO #ifdef USE_SSL /*
@@ -463,7 +464,7 @@ static inline void socks_postprocess_incoming_link (struct context *c) {if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) -socks_process_incoming_udp (&c->c2.buf, &c->c2.from); +socks_process_incoming_udp (&c->c2.buf, &c->c2.incoming_from); } static inline void
@@ -505,7 +506,8 @@ read_incoming_link (struct context *c) c->c2.buf = c->c2.buffers->read_link_buf;ASSERT (buf_init (&c->c2.buf,FRAME_HEADROOM (&c->c2.frame))); - status =link_socket_read (c->c2.link_socket, &c->c2.buf,MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from); + status =link_socket_read (c->c2.link_socket, &c->c2.buf,MAX_RW_SIZE_LINK (&c->c2.frame), + &c->c2.incoming_from, &c->c2.incoming_to);if (socket_connection_reset (c->c2.link_socket, status)) {
@@ -561,7 +563,7 @@ process_incoming_link (struct context *cmsg (D_LINK_RW ,"%s READ [%d] from %s: %s" ,proto2ascii (lsi->proto, true),BLEN (&c->c2.buf), -print_sockaddr (&c->c2.from, &gc), +print_sockaddr (&c->c2.incoming_from, &gc),PROTO_DUMP (&c->c2.buf, &gc));/*
@@ -573,8 +575,8 @@ process_incoming_link (struct context *c*/ if (c->c2.buf.len >0 ) { -if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from)) -link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from); +if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.incoming_from)) +link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.incoming_from);#ifdef USE_CRYPTO #ifdef USE_SSL
@@ -591,7 +593,9 @@ process_incoming_link (struct context *c* and return false. */ //tls_mutex_lock (c->c2.tls_multi); -if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options)) +if (tls_pre_decrypt (c->c2.tls_multi, + &c->c2.incoming_from, &c->c2.incoming_to, + &c->c2.buf, &c->c2.crypto_options)) {interval_action (&c->c2.tmp_int);
@@ -641,7 +645,7 @@ process_incoming_link (struct context *c* Also, update the persisted version of our packet-id. */ if (!TLS_MODE ) -link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.from,NULL ); +link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.incoming_from, &c->c2.incoming_to,NULL );/* reset packet received timer */ if (c->options.ping_rec_timeout && c->c2.buf.len >0 )
@@ -826,7 +830,8 @@ process_outgoing_link (struct context *csocks_preprocess_outgoing_link (c, &to_addr, &size_delta);/* Send packet */ - size =link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr); + size =link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr, + &c->c2.from_link_addr);/* Undo effect of prepend */ link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link);
multi.c renamed from multi.c~current~ +6 -4
@@ -544,7 +544,7 @@ multi_get_create_instance (struct multi_struct multi_instance *mi =NULL ;struct hash *hash = mt->multi->hash; -if (mroute_extract_sockaddr_in (&real, &mt->top.c2.from, true)) +if (mroute_extract_sockaddr_in (&real, &mt->top.c2.incoming_from, true)) {struct hash_element *he;const uint32_t hv =hash_value (hash, &real);
@@ -560,7 +560,8 @@ multi_get_create_instance (struct multi_else {if (!mt->top.c2.tls_auth_standalone - ||tls_pre_decrypt_lite (mt->top.c2.tls_auth_standalone, &mt->top.c2.from, &mt->top.c2.buf)) + ||tls_pre_decrypt_lite (mt->top.c2.tls_auth_standalone, + &mt->top.c2.incoming_from, &mt->top.c2.incoming_to, &mt->top.c2.buf)) {if (frequency_limit_event_allowed (mt->multi->new_connection_limiter)) {
@@ -1330,8 +1331,9 @@ multi_process_incoming_link (struct mult/* transfer packet pointer from top-level context buffer to instance */ c->c2.buf = mt->top.c2.buf; -/* transfer from-addr from top-level context buffer to instance */ - c->c2.from = mt->top.c2.from; +/* transfer from-addr and to-addr from top-level context buffer to instance */ + c->c2.incoming_from = mt->top.c2.incoming_from; + c->c2.incoming_to = mt->top.c2.incoming_to;/* decrypt in instance context */ process_incoming_link (c);
openvpn.h renamed from openvpn.h~current~ +4 -1
@@ -167,7 +167,10 @@ struct context_2const struct link_socket *accept_from;/* possibly do accept() on a parent link_socket */ struct sockaddr_in to_link_addr;/* IP address of remote */ -struct sockaddr_in from;/* address of incoming datagram */ +struct sockaddr_in from_link_addr;/* Address to send messages from */ + +struct sockaddr_in incoming_from;/* address of incoming datagram */ +struct sockaddr_in incoming_to;/* address incoming datagram was to */ /* MTU frame parameters */ struct frame frame;
socket.c renamed from socket.c~current~ +45 -1
76 lines not on this page · raw message
socket.h renamed from socket.h~current~ +56 -11
149 lines not on this page · raw message
ssl.c renamed from ssl.c~current~ +19 -6
@@ -1494,6 +1494,7 @@ write_control_auth (struct tls_session *struct key_state *ks, struct buffer *buf, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, int opcode, int max_ack, bool prepend_ack)
@@ -1514,6 +1515,7 @@ write_control_auth (struct tls_session *ASSERT (swap_hmac (buf, &session->tls_auth, false)); } *to_link_addr = ks->remote_addr; + *from_link_addr = ks->local_addr; }/*
@@ -1916,6 +1918,7 @@ key_state_soft_reset (struct tls_sessionkey_state_init (session, ks); ks->session_id_remote = ks_lame->session_id_remote; ks->remote_addr = ks_lame->remote_addr; + ks->local_addr = ks_lame->local_addr; }/*
@@ -1932,6 +1935,7 @@ tls_process (struct tls_multi *multi,struct tls_session *session, struct buffer *to_link, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) {
@@ -2052,7 +2056,8 @@ tls_process (struct tls_multi *multi,INCR_SUCCESS ;/* Set outgoing address for data channel packets */ -link_socket_set_outgoing_addr (NULL , to_link_socket_info, &ks->remote_addr, session->common_name); +link_socket_set_outgoing_addr (NULL , to_link_socket_info, &ks->remote_addr, + &ks->local_addr, session->common_name);#ifdef MEASURE_TLS_HANDSHAKE_STATS show_tls_performance_stats ();
@@ -2072,7 +2077,8 @@ tls_process (struct tls_multi *multi, b = *buf;INCR_SENT ; -write_control_auth (session, ks, &b, to_link_addr, opcode, +write_control_auth (session, ks, &b, to_link_addr, + from_link_addr, opcode,CONTROL_SEND_ACK_MAX , true); *to_link = b; active = true;
@@ -2087,7 +2093,8 @@ tls_process (struct tls_multi *multi, { buf = &ks->ack_write_buf;ASSERT (buf_init (buf,FRAME_HEADROOM (&multi->opt.frame))); -write_control_auth (session, ks, buf, to_link_addr,P_ACK_V1 , +write_control_auth (session, ks, buf, to_link_addr, from_link_addr, +P_ACK_V1 ,RELIABLE_ACK_SIZE , false); *to_link = *buf; active = true;
@@ -2391,7 +2398,7 @@ tls_process (struct tls_multi *multi, { buf = &ks->ack_write_buf;ASSERT (buf_init (buf,FRAME_HEADROOM (&multi->opt.frame))); -write_control_auth (session, ks, buf, to_link_addr,P_ACK_V1 , +write_control_auth (session, ks, buf, to_link_addr, from_link_addr,P_ACK_V1 ,RELIABLE_ACK_SIZE , false); *to_link = *buf; active = true;
@@ -2453,6 +2460,7 @@ bool tls_multi_process (struct tls_multi *multi, struct buffer *to_link, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) {
@@ -2473,8 +2481,10 @@ tls_multi_process (struct tls_multi *mul/* set initial remote address */ if (i ==TM_ACTIVE && ks->state ==S_INITIAL && -addr_defined (&to_link_socket_info->lsa->actual)) +addr_defined (&to_link_socket_info->lsa->actual)) { ks->remote_addr = to_link_socket_info->lsa->actual; + ks->local_addr = to_link_socket_info->lsa->actuallocal; + } msg (D_TLS_DEBUG, "TLS: tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s, stored-ip=%s",
@@ -2488,7 +2498,7 @@ tls_multi_process (struct tls_multi *mul {update_time (); -if (tls_process (multi, session, to_link, to_link_addr, +if (tls_process (multi, session, to_link, to_link_addr, from_link_addr, to_link_socket_info, wakeup)) active = true;
@@ -2617,6 +2627,7 @@ tls_rec_payload (struct tls_multi *multibool tls_pre_decrypt (struct tls_multi *multi,struct sockaddr_in *from, +struct sockaddr_in *to,struct buffer *buf,struct crypto_options *opt) {
@@ -2919,6 +2930,7 @@ tls_pre_decrypt (struct tls_multi *multi { ks->session_id_remote = sid; ks->remote_addr = *from; + ks->local_addr = *to; ++multi->n_sessions; } else if (!addr_port_match (&ks->remote_addr, from))
@@ -3023,6 +3035,7 @@ tls_pre_decrypt (struct tls_multi *multibool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,const struct sockaddr_in *from, +const struct sockaddr_in *to,const struct buffer *buf) {struct gc_arena gc =gc_new ();
ssl.h renamed from ssl.h~current~ +4 -0
@@ -236,6 +236,7 @@ struct key_stateint initial_opcode;/* our initial P_ opcode */ struct session_id session_id_remote;/* peer's random session ID */ struct sockaddr_in remote_addr;/* peer's IP addr */ +struct sockaddr_in local_addr;/* address peer expects reply from */ struct packet_id packet_id;/* for data channel, to prevent replay attacks */ struct key_ctx_bi key;/* data channel keys for encrypt/decrypt/hmac */
@@ -456,6 +457,7 @@ void tls_multi_init_set_options(struct tbool tls_multi_process (struct tls_multi *multi,struct buffer *to_link,struct sockaddr_in *to_link_addr, +struct sockaddr_in *from_link_addr,struct link_socket_info *to_link_socket_info,interval_t *wakeup);
@@ -463,11 +465,13 @@ void tls_multi_free (struct tls_multi *mbool tls_pre_decrypt (struct tls_multi *multi,struct sockaddr_in *from, +struct sockaddr_in *to,struct buffer *buf,struct crypto_options *opt);bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,const struct sockaddr_in *from, +const struct sockaddr_in *to,const struct buffer *buf); void tls_pre_encrypt (struct tls_multi *multi,
Neil,
Thanks for the patches... here are some comments:
* You've obviously put a lot of effort into understanding the code to write this patch. But did you consider any alternative approaches, such as starting multiple OpenVPN instances and binding each to a separate local interface?
* A lot of function prototypes get changed so that both from and to sockaddr_in pointers must be passed. Do you think it might make more sense to make a new struct that represents a bidirectional socketaddr_in and embed from and to inside of it? I'm mostly thinking about this from the angle of easing future maintenance. As much as is possible, I would like to see this patch live in it's own location (probably a separate source file) and require a minimal amount of modification of existing code.
* It would be nice to see the #ifdef IP_PKTINFO code (which appears to be non-portable) isolated somewhere and bracketed inside of an internal API which would make it easy for different cases to be implemented for different OSes.
* The change to link_socket_set_outgoing_addr is probably okay, though remember that this is in the main line event loop, so efficiency is important here. Most of link_socket_set_outgoing_addr is structured around the fact that a bunch of special things need to happen if the remote address changes, but what similar kinds of things need to happen when the local address changes?
James
Quoted 87 lines · Neil Brown
Hi.
This is the first of 4 patches that I would like to offer for openvpn.
They are against 2.0_beta7.This first one is a refinement of a patch I posted earlier which, at that time, didn't work.
The purpose of the patch is to use theIP_PKTINFOsocket option to get and set the local address for UDP packets being sent or received. This means that if you have a multihomed server, then packets sent to it will always come from the address that they corresponding packets were sent to. This is needed to pass cleanly through a NAT.In replaces "struct
sockaddr_infrom" in "structcontext_2" with
structsockaddr_inincoming_from,incoming_to
and records the address provided byIP_PKTINFOinincoming_to.It adds "struct
sockaddr_inactuallocal" alongside "structsockaddr_inactual" in "structlock_socket_addr", for storing the local enpoint if a udp "connection" in this structure.It adds "struct
sockaddr_inlocal_addr" alongside "remote_addr" in "structkey_state" for a similar purpose.And it makes sure these fields are set and used appropriately.
The main reason that it didn't work before was that in
multi_process_incoming_link, when the packet and address are transferred from the "mt" structure into the per-session context structure, I wasn't copying theincoming_toaddress as well. I do now.One part of the change that I am not completely happy with is
socket.h renamed from socket.h~current~ +2
-0+/* alway set localaddr address */ + info->lsa->actuallocal = *localaddr;in
link_socket_set_outgoing_addr.
The current code only changes the outgoing address if it has changed, and it does that insidelink_socket_connection_initiated. However it is possible for the localaddress to change without the remote address changing.
e.g. If I stop and restart my openvpn instance on my notebook, and it gets a different IP address via DNS lookup. In this case it will appear to be a continuation of the same session, but will need to use a different local address. I think it is OK to change the localaddress on every packet, but I am open to be convinced otherwise, or that the code could be cleaner.Anyway, here is the patch. I hope it can be included in an upcoming beta of openvpn.
Thanks,
NeilBrown============================================
### Diffstat output
./forward.c | 23 ++++++++++++-------- ./multi.c | 10 +++++--- ./openvpn.h | 5 +++- ./socket.c | 46 ++++++++++++++++++++++++++++++++++++++++- ./socket.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- ./ssl.c | 25 +++++++++++++++++----- ./ssl.h | 4 +++ 7 files changed, 148 insertions(+), 32 deletions(-)diff ./forward.c~current~ ./forward.c
forward.c renamed from forward.c~current~ +2
-1@@ -87,6 +87,7 @@ check_tls_dowork (struct context *c) {if (tls_multi_process (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, + &c->c2.from_link_addr,get_link_socket_info (c), &wakeup)) {update_time ();@@ -342,7 +343,7 @@ encrypt_sign (struct context *c, bool co* Get the address we will be sending the packet to. */ link_socket_get_outgoing_addr (&c->c2.buf,get_link_socket_info (c), - &c->c2.to_link_addr); + &c->c2.to_link_addr, &c->c2.from_link_addr);#ifdef USE_CRYPTO #ifdef USE_SSL /*
forward.c static inline void · line 466
Quoted 3 lines
forward.c renamed from forward.c~current~ +0
-0@@ -463,7 +464,7 @@ static inline void socks_postprocess_incoming_link (struct context *c) { if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto ==
PROTO_UDPv4)
forward.c read_incoming_link (struct context *c) · line 508
Quoted 10 lines
forward.c renamed from forward.c~current~ +1
-2-socks_process_incoming_udp (&c->c2.buf, &c->c2.from); +socks_process_incoming_udp (&c->c2.buf, &c->c2.incoming_from); } static inline void@@ -505,7 +506,8 @@ read_incoming_link (struct context *c) c->c2.buf = c->c2.buffers->read_link_buf;ASSERT (buf_init (&c->c2.buf,FRAME_HEADROOM (&c->c2.frame))); - status = link_socket_read (c->c2.link_socket, &c->c2.buf,
MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from);
forward.c read_incoming_link (struct context *c) · line 509
Quoted 1 line
forward.c renamed from forward.c~current~ +1
-0+ status = link_socket_read (c->c2.link_socket, &c->c2.buf,
MAX_RW_SIZE_LINK (&c->c2.frame),
Quoted 14 lines
forward.c renamed from forward.c~current~ +2
-1+ &c->c2.incoming_from, &c->c2.incoming_to);if (socket_connection_reset (c->c2.link_socket, status)) {@@ -561,7 +563,7 @@ process_incoming_link (struct context *cmsg (D_LINK_RW ,"%s READ [%d] from %s: %s" ,proto2ascii (lsi->proto, true),BLEN (&c->c2.buf), -print_sockaddr (&c->c2.from, &gc), +print_sockaddr (&c->c2.incoming_from, &gc),PROTO_DUMP (&c->c2.buf, &gc));/*
forward.c process_incoming_link (struct context *c · line 578
Quoted 6 lines
forward.c renamed from forward.c~current~ +1
-2@@ -573,8 +575,8 @@ process_incoming_link (struct context *c*/ if (c->c2.buf.len > 0) { -if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from)) -link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from); + if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi,
&c->c2.incoming_from))
forward.c process_incoming_link (struct context *c · line 594
Quoted 9 lines
forward.c renamed from forward.c~current~ +1
-1+link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.incoming_from);#ifdef USE_CRYPTO #ifdef USE_SSL @@ -591,7 +593,9 @@ process_incoming_link (struct context *c* and return false. */ //tls_mutex_lock (c->c2.tls_multi); - if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf,
&c->c2.crypto_options))
forward.c process_incoming_link (struct context *c · line 648
Quoted 12 lines
forward.c renamed from forward.c~current~ +4
-1+if (tls_pre_decrypt (c->c2.tls_multi, + &c->c2.incoming_from, &c->c2.incoming_to, + &c->c2.buf, &c->c2.crypto_options)) {interval_action (&c->c2.tmp_int);@@ -641,7 +645,7 @@ process_incoming_link (struct context *c* Also, update the persisted version of our packet-id. */ if (!TLS_MODE ) -link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.from,NULL ); + link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.incoming_from,
&c->c2.incoming_to, NULL);
Quoted 27 lines
forward.c renamed from forward.c~current~ +2
-1/* reset packet received timer */ if (c->options.ping_rec_timeout && c->c2.buf.len >0 )@@ -826,7 +830,8 @@ process_outgoing_link (struct context *csocks_preprocess_outgoing_link (c, &to_addr, &size_delta);/* Send packet */ - size =link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr); + size =link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr, + &c->c2.from_link_addr);/* Undo effect of prepend */ link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link);diff ./multi.c~current~ ./multi.c
multi.c renamed from multi.c~current~ +1
-1@@ -544,7 +544,7 @@ multi_get_create_instance (struct multi_struct multi_instance *mi =NULL ;struct hash *hash = mt->multi->hash; -if (mroute_extract_sockaddr_in (&real, &mt->top.c2.from, true)) +if (mroute_extract_sockaddr_in (&real, &mt->top.c2.incoming_from, true)) {struct hash_element *he;const uint32_t hv =hash_value (hash, &real);
multi.c multi_get_create_instance (struct multi_ · line 563
Quoted 4 lines
multi.c renamed from multi.c~current~ +0
-1@@ -560,7 +560,8 @@ multi_get_create_instance (struct multi_else { if (!mt->top.c2.tls_auth_standalone - || tls_pre_decrypt_lite (mt->top.c2.tls_auth_standalone,
&mt->top.c2.from, &mt->top.c2.buf))
multi.c multi_get_create_instance (struct multi_ · line 564
Quoted 2 lines
multi.c renamed from multi.c~current~ +2
-0+ || tls_pre_decrypt_lite (mt->top.c2.tls_auth_standalone, + &mt->top.c2.incoming_from, &mt->top.c2.incoming_to,
&mt->top.c2.buf))
multi.c multi_process_incoming_link (struct mult · line 1334
Quoted 10 lines
multi.c renamed from multi.c~current~ +1
-2{if (frequency_limit_event_allowed (mt->multi->new_connection_limiter)) {@@ -1330,8 +1331,9 @@ multi_process_incoming_link (struct mult/* transfer packet pointer from top-level context buffer to instance */ c->c2.buf = mt->top.c2.buf; -/* transfer from-addr from top-level context buffer to instance */ - c->c2.from = mt->top.c2.from; +/* transfer from-addr and to-addr from top-level context buffer to
instance */
openvpn.h struct context_2 · line 167
Quoted 11 lines
multi.c renamed from multi.c~current~ +2
-0+ c->c2.incoming_from = mt->top.c2.incoming_from; + c->c2.incoming_to = mt->top.c2.incoming_to;/* decrypt in instance context */ process_incoming_link (c);diff ./openvpn.h~current~ ./openvpn.h
openvpn.h renamed from openvpn.h~current~ +0
-0@@ -167,7 +167,10 @@ struct context_2const struct link_socket *accept_from;/* possibly do accept() on a
parent link_socket */
Quoted 247 lines
openvpn.h renamed from openvpn.h~current~ +4
-1struct sockaddr_in to_link_addr;/* IP address of remote */ -struct sockaddr_in from;/* address of incoming datagram */ +struct sockaddr_in from_link_addr;/* Address to send messages from */ + +struct sockaddr_in incoming_from;/* address of incoming datagram */ +struct sockaddr_in incoming_to;/* address incoming datagram was to */ /* MTU frame parameters */ struct frame frame;diff ./socket.c~current~ ./socket.c
socket.c renamed from socket.c~current~ +45
-1@@ -392,6 +392,12 @@ create_socket_udp (void)if ((sd =socket (PF_INET ,SOCK_DGRAM ,IPPROTO_UDP )) <0 )msg (M_SOCKERR ,"UDP: Cannot create UDP socket" ); +#ifdef IP_PKTINFO + else { +int pad =1 ; +setsockopt (sd,SOL_IP ,IP_PKTINFO , (void *)&pad,sizeof (pad)); + } +#endif return sd; }@@ -1135,6 +1141,7 @@ void link_socket_connection_initiated (const struct buffer *buf, struct link_socket_info *info, const struct sockaddr_in *addr, + const struct sockaddr_in *localaddr, const char *common_name) { struct gc_arena gc = gc_new ();@@ -1143,6 +1150,7 @@ link_socket_connection_initiated (constmutex_lock_static (L_SCRIPT ); info->lsa->actual = *addr;/* Note: skip this line for --force-dest */ + info->lsa->actuallocal = *localaddr;setenv_trusted (info); info->connection_established = true;@@ -1582,13 +1590,49 @@ int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from) + struct sockaddr_in *from, + struct sockaddr_in *to) { socklen_t fromlen = sizeof (*from);CLEAR (*from); +CLEAR (*to);ASSERT (buf_safe (buf, maxsize)); +#ifdef IP_PKTINFO + { +struct iovec iov; +char b[sizeof (struct cmsghdr )+sizeof (struct in_pktinfo )]; +struct msghdr mesg; + iov.iov_base =BPTR (buf); + iov.iov_len = maxsize; + mesg.msg_iov = &iov; + mesg.msg_iovlen =1 ; + mesg.msg_name = from; + mesg.msg_namelen = fromlen; + mesg.msg_control = b; + mesg.msg_controllen =sizeof (b); +CLEAR (*to); + buf->len =recvmsg (sock->sd, &mesg,0 ); +if (buf->len >=0 ) + { +struct cmsghdr *cmsg; + fromlen = mesg.msg_namelen; + cmsg =CMSG_FIRSTHDR (&mesg); +if (cmsg !=NULL + &&CMSG_NXTHDR (&mesg, cmsg) ==NULL + && cmsg->cmsg_level ==SOL_IP + && cmsg->cmsg_type ==IP_PKTINFO + && cmsg->cmsg_len >= (sizeof (struct cmsghdr ) + +sizeof (struct in_pktinfo ))) + { +struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA (cmsg); + to->sin_addr = pkti->ipi_addr; + } + } + } +#else buf->len =recvfrom (sock->sd,BPTR (buf), maxsize,0 , (struct sockaddr *) from, &fromlen); +#endif if (fromlen !=sizeof (*from))bad_address_length (fromlen,sizeof (*from));return buf->len;diff ./socket.h~current~ ./socket.h
socket.h renamed from socket.h~current~ +53
-9@@ -70,6 +70,7 @@ struct link_socket_addrstruct sockaddr_in local;struct sockaddr_in remote;/* initial remote */ struct sockaddr_in actual;/* remote may change due to --float */ +struct sockaddr_in actuallocal;/* make sure we reply from right address */ };struct link_socket_info @@ -273,6 +274,7 @@ in_addr_t link_socket_current_remote (covoid link_socket_connection_initiated (const struct buffer *buf,struct link_socket_info *info,const struct sockaddr_in *addr, +const struct sockaddr_in *localaddr,const char *common_name); void link_socket_bad_incoming_addr (struct buffer *buf,@@ -443,7 +445,8 @@ link_socket_verify_incoming_addr (structstatic inline void link_socket_get_outgoing_addr (struct buffer *buf,const struct link_socket_info *info, -struct sockaddr_in *addr) +struct sockaddr_in *addr, +struct sockaddr_in *fromaddr) {if (buf->len >0 ) {@@ -453,6 +456,10 @@ link_socket_get_outgoing_addr (struct bu addr->sin_family = lsa->actual.sin_family; addr->sin_addr.s_addr = lsa->actual.sin_addr.s_addr; addr->sin_port = lsa->actual.sin_port; + + fromaddr->sin_family = lsa->actuallocal.sin_family; + fromaddr->sin_addr.s_addr = lsa->actuallocal.sin_addr.s_addr; + fromaddr->sin_port = lsa->actuallocal.sin_port; }else {@@ -466,6 +473,7 @@ static inline void link_socket_set_outgoing_addr (const struct buffer *buf, struct link_socket_info *info, const struct sockaddr_in *addr, + const struct sockaddr_in *localaddr, const char *common_name) { if (!buf || buf->len > 0)@@ -481,8 +489,10 @@ link_socket_set_outgoing_addr (const str || addr_match_proto (addr, &lsa->remote, info->proto)) ) { -link_socket_connection_initiated (buf, info, addr, common_name); +link_socket_connection_initiated (buf, info, addr, localaddr, common_name); } +/* alway set localaddr address */ + info->lsa->actuallocal = *localaddr; } }@@ -528,7 +538,8 @@ link_socket_read_udp_win32 (struct link_int link_socket_read_udp_posix (struct link_socket *sock,struct buffer *buf,int maxsize, -struct sockaddr_in *from); +struct sockaddr_in *from, +struct sockaddr_in *to);#endif @@ -537,16 +548,17 @@ static inline int link_socket_read (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from) + struct sockaddr_in *from, + struct sockaddr_in *to) { if (sock->info.proto == PROTO_UDPv4) { int res; - +CLEAR (*to);#ifdef WIN32 res =link_socket_read_udp_win32 (sock, buf, from);#else - res =link_socket_read_udp_posix (sock, buf, maxsize, from); + res =link_socket_read_udp_posix (sock, buf, maxsize, from, to);#endif return res; }@@ -601,8 +613,39 @@ link_socket_write_win32 (struct link_socstatic inline int link_socket_write_udp_posix (struct link_socket *sock,struct buffer *buf, -struct sockaddr_in *to) +struct sockaddr_in *to, +struct sockaddr_in *from) { +#ifdef IP_PKTINFO +if (addr_defined (from)) + { +struct iovec iov; +struct msghdr mesg; +struct cmsghdr *cmsg; +struct in_pktinfo *pkti; + +char b[sizeof (struct cmsghdr )+sizeof (struct in_pktinfo )]; + iov.iov_base =BPTR (buf); + iov.iov_len =BLEN (buf); + mesg.msg_iov = &iov; + mesg.msg_iovlen =1 ; + mesg.msg_name = to; + mesg.msg_namelen =sizeof (*to); + mesg.msg_control = b; + mesg.msg_controllen =sizeof (b); + mesg.msg_flags =0 ; + cmsg =CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len =sizeof (b); + cmsg->cmsg_level =SOL_IP ; + cmsg->cmsg_type =IP_PKTINFO ; + pkti = (struct in_pktinfo *)CMSG_DATA (cmsg); + pkti->ipi_ifindex =0 ; + pkti->ipi_spec_dst = from->sin_addr; + pkti->ipi_addr = from->sin_addr; + +return sendmsg (sock->sd, &mesg,0 ); + } +#endif return sendto (sock->sd,BPTR (buf),BLEN (buf),0 , (struct sockaddr *) to, (socklen_t )sizeof (*to));@@ -621,12 +664,13 @@ link_socket_write_tcp_posix (struct linkstatic inline int link_socket_write_udp (struct link_socket *sock,struct buffer *buf, -struct sockaddr_in *to) +struct sockaddr_in *to, +struct sockaddr_in *from) {#ifdef WIN32 return link_socket_write_win32 (sock, buf, to);#else -return link_socket_write_udp_posix (sock, buf, to); +return link_socket_write_udp_posix (sock, buf, to, from);#endif }@@ -634,11 +678,12 @@ link_socket_write_udp (struct link_socke static inline int link_socket_write (struct link_socket *sock, struct buffer *buf,
socket.h link_socket_write_udp (struct link_socke · line 688
Quoted 10 lines
socket.h renamed from socket.h~current~ +3
-2- struct sockaddr_in *to) + struct sockaddr_in *to, + struct sockaddr_in *from) { if (sock->info.proto == PROTO_UDPv4) { - return link_socket_write_udp (sock, buf, to); + return link_socket_write_udp (sock, buf, to, from); } else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto ==
PROTO_TCPv4_CLIENT)
Quoted 38 lines
socket.h renamed from socket.h~current~ +0
-0{diff ./ssl.c~current~ ./ssl.c
ssl.c renamed from ssl.c~current~ +4
-0@@ -1494,6 +1494,7 @@ write_control_auth (struct tls_session *struct key_state *ks, struct buffer *buf, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, int opcode, int max_ack, bool prepend_ack)@@ -1514,6 +1515,7 @@ write_control_auth (struct tls_session *ASSERT (swap_hmac (buf, &session->tls_auth, false)); } *to_link_addr = ks->remote_addr; + *from_link_addr = ks->local_addr; }/* @@ -1916,6 +1918,7 @@ key_state_soft_reset (struct tls_sessionkey_state_init (session, ks); ks->session_id_remote = ks_lame->session_id_remote; ks->remote_addr = ks_lame->remote_addr; + ks->local_addr = ks_lame->local_addr; }/* @@ -1932,6 +1935,7 @@ tls_process (struct tls_multi *multi,struct tls_session *session, struct buffer *to_link, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) {
ssl.c tls_process (struct tls_multi *multi, · line 2055
Quoted 4 lines
ssl.c renamed from ssl.c~current~ +0
-1@@ -2052,7 +2056,8 @@ tls_process (struct tls_multi *multi,INCR_SUCCESS ;/* Set outgoing address for data channel packets */ - link_socket_set_outgoing_addr (NULL, to_link_socket_info,
&ks->remote_addr, session->common_name);
Quoted 26 lines
ssl.c renamed from ssl.c~current~ +6
-2+link_socket_set_outgoing_addr (NULL , to_link_socket_info, &ks->remote_addr, + &ks->local_addr, session->common_name);#ifdef MEASURE_TLS_HANDSHAKE_STATS show_tls_performance_stats ();@@ -2072,7 +2077,8 @@ tls_process (struct tls_multi *multi, b = *buf;INCR_SENT ; -write_control_auth (session, ks, &b, to_link_addr, opcode, +write_control_auth (session, ks, &b, to_link_addr, + from_link_addr, opcode,CONTROL_SEND_ACK_MAX , true); *to_link = b; active = true;@@ -2087,7 +2093,8 @@ tls_process (struct tls_multi *multi, { buf = &ks->ack_write_buf;ASSERT (buf_init (buf,FRAME_HEADROOM (&multi->opt.frame))); -write_control_auth (session, ks, buf, to_link_addr,P_ACK_V1 , +write_control_auth (session, ks, buf, to_link_addr, from_link_addr, +P_ACK_V1 ,RELIABLE_ACK_SIZE , false); *to_link = *buf; active = true;
ssl.c tls_process (struct tls_multi *multi, · line 2401
Quoted 5 lines
ssl.c renamed from ssl.c~current~ +1
-1@@ -2391,7 +2398,7 @@ tls_process (struct tls_multi *multi, { buf = &ks->ack_write_buf;ASSERT (buf_init (buf,FRAME_HEADROOM (&multi->opt.frame))); - write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1, + write_control_auth (session, ks, buf, to_link_addr, from_link_addr,
P_ACK_V1,
Quoted 13 lines
ssl.c renamed from ssl.c~current~ +1
-0RELIABLE_ACK_SIZE, false); *to_link = *buf; active = true;@@ -2453,6 +2460,7 @@ bool tls_multi_process (struct tls_multi *multi, struct buffer *to_link, struct sockaddr_in *to_link_addr, + struct sockaddr_in *from_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) {@@ -2473,8 +2481,10 @@ tls_multi_process (struct tls_multi *mul
ssl.c tls_multi_process (struct tls_multi *mul · line 2490
Quoted 10 lines
ssl.c renamed from ssl.c~current~ +3
-1/* set initial remote address */ if (i ==TM_ACTIVE && ks->state ==S_INITIAL && -addr_defined (&to_link_socket_info->lsa->actual)) +addr_defined (&to_link_socket_info->lsa->actual)) { ks->remote_addr = to_link_socket_info->lsa->actual; + ks->local_addr = to_link_socket_info->lsa->actuallocal; + } msg (D_TLS_DEBUG, "TLS: tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s,
stored-ip=%s",
Quoted 38 lines
ssl.c renamed from ssl.c~current~ +4
-1@@ -2488,7 +2498,7 @@ tls_multi_process (struct tls_multi *mul {update_time (); -if (tls_process (multi, session, to_link, to_link_addr, +if (tls_process (multi, session, to_link, to_link_addr, from_link_addr, to_link_socket_info, wakeup)) active = true;@@ -2617,6 +2627,7 @@ tls_rec_payload (struct tls_multi *multibool tls_pre_decrypt (struct tls_multi *multi,struct sockaddr_in *from, +struct sockaddr_in *to,struct buffer *buf,struct crypto_options *opt) {@@ -2919,6 +2930,7 @@ tls_pre_decrypt (struct tls_multi *multi { ks->session_id_remote = sid; ks->remote_addr = *from; + ks->local_addr = *to; ++multi->n_sessions; } else if (!addr_port_match (&ks->remote_addr, from))@@ -3023,6 +3035,7 @@ tls_pre_decrypt (struct tls_multi *multibool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,const struct sockaddr_in *from, +const struct sockaddr_in *to,const struct buffer *buf) {struct gc_arena gc =gc_new ();diff ./ssl.h~current~ ./ssl.h
ssl.h struct key_state · line 240
Quoted 5 lines
ssl.h renamed from ssl.h~current~ +1
-0@@ -236,6 +236,7 @@ struct key_stateint initial_opcode;/* our initial P_ opcode */ struct session_id session_id_remote;/* peer's random session ID */ struct sockaddr_in remote_addr;/* peer's IP addr */ +struct sockaddr_in local_addr;/* address peer expects reply from */ struct packet_id packet_id;/* for data channel, to prevent replay
attacks */
ssl.h struct key_state · line 241
Quoted 2 lines
ssl.h renamed from ssl.h~current~ +0
-0struct key_ctx_bi key;/* data channel keys for
encrypt/decrypt/hmac */
Quoted 24 lines
ssl.h renamed from ssl.h~current~ +3
-0@@ -456,6 +457,7 @@ void tls_multi_init_set_options(struct tbool tls_multi_process (struct tls_multi *multi,struct buffer *to_link,struct sockaddr_in *to_link_addr, +struct sockaddr_in *from_link_addr,struct link_socket_info *to_link_socket_info,interval_t *wakeup);@@ -463,11 +465,13 @@ void tls_multi_free (struct tls_multi *mbool tls_pre_decrypt (struct tls_multi *multi,struct sockaddr_in *from, +struct sockaddr_in *to,struct buffer *buf,struct crypto_options *opt);bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,const struct sockaddr_in *from, +const struct sockaddr_in *to,const struct buffer *buf); void tls_pre_encrypt (struct tls_multi *multi,
Quoted 8 lines · James Yonan
Neil,
Thanks for the patches... here are some comments:
* You've obviously put a lot of effort into understanding the code to write this patch. But did you consider any alternative approaches, such as starting multiple OpenVPN instances and binding each to a separate local interface?
This will fail for dynamic ip addresses and dynamic interfaces. Also it will incur memory and context switch time penalties. Just imagine a host with 100 ip addresses.
--
vda