diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-10-15 08:44:02 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-10-15 08:44:02 +0000 |
commit | 8bc93d7ffbc127e0b095c7274a68eb0c175f93ae (patch) | |
tree | be0d71b15492041caeb3deb1ac923123a44ea96e /socket.c | |
parent | Merged --capath patch (Thomas Noel). (diff) | |
download | openvpn-8bc93d7ffbc127e0b095c7274a68eb0c175f93ae.tar.xz |
svn merge -r 618:619 $SO/patches/openvpn-2-0_rc16-mh/openvpn
Merged --multihome patch + aggregated sockflags.
Pre-2.1_beta3
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@622 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'socket.c')
-rw-r--r-- | socket.c | 337 |
1 files changed, 246 insertions, 91 deletions
@@ -236,7 +236,7 @@ openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr) static void update_remote (const char* host, - struct sockaddr_in *addr, + struct openvpn_sockaddr *addr, bool *changed) { if (host && addr) @@ -247,9 +247,9 @@ update_remote (const char* host, 1, NULL, NULL); - if (new_addr && addr->sin_addr.s_addr != new_addr) + if (new_addr && addr->sa.sin_addr.s_addr != new_addr) { - addr->sin_addr.s_addr = new_addr; + addr->sa.sin_addr.s_addr = new_addr; *changed = true; } } @@ -492,12 +492,19 @@ create_socket_tcp (void) } static socket_descriptor_t -create_socket_udp (void) +create_socket_udp (const unsigned int flags) { socket_descriptor_t sd; if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) msg (M_SOCKERR, "UDP: Cannot create UDP socket"); +#if ENABLE_IP_PKTINFO + else if (flags & SF_USE_IP_PKTINFO) + { + int pad = 1; + setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad)); + } +#endif return sd; } @@ -507,7 +514,7 @@ create_socket (struct link_socket *sock) /* create socket */ if (sock->info.proto == PROTO_UDPv4) { - sock->sd = create_socket_udp (); + sock->sd = create_socket_udp (sock->sockflags); #ifdef ENABLE_SOCKS if (sock->socks_proxy) @@ -531,7 +538,7 @@ create_socket (struct link_socket *sock) static void socket_do_listen (socket_descriptor_t sd, - const struct sockaddr_in *local, + const struct openvpn_sockaddr *local, bool do_listen, bool do_set_nonblock) { @@ -553,16 +560,18 @@ socket_do_listen (socket_descriptor_t sd, socket_descriptor_t socket_do_accept (socket_descriptor_t sd, - struct sockaddr_in *remote, + struct link_socket_actual *act, const bool nowait) { - socklen_t remote_len = sizeof (*remote); + socklen_t remote_len = sizeof (act->dest.sa); socket_descriptor_t new_sd = SOCKET_UNDEFINED; + CLEAR (*act); + #ifdef HAVE_GETPEERNAME if (nowait) { - new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len); + new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len); if (!socket_defined (new_sd)) msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed"); @@ -575,14 +584,14 @@ socket_do_accept (socket_descriptor_t sd, #endif else { - new_sd = accept (sd, (struct sockaddr *) remote, &remote_len); + new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len); } if (!socket_defined (new_sd)) { msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd); } - else if (remote_len != sizeof (*remote)) + else if (remote_len != sizeof (act->dest.sa)) { msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); openvpn_close_socket (new_sd); @@ -592,28 +601,30 @@ socket_do_accept (socket_descriptor_t sd, } static void -tcp_connection_established (const struct sockaddr_in *remote) +tcp_connection_established (const struct link_socket_actual *act) { struct gc_arena gc = gc_new (); msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + print_link_socket_actual (act, &gc)); gc_free (&gc); } static int socket_listen_accept (socket_descriptor_t sd, - struct sockaddr_in *remote, + struct link_socket_actual *act, const char *remote_dynamic, bool *remote_changed, - const struct sockaddr_in *local, + const struct openvpn_sockaddr *local, bool do_listen, bool nowait, volatile int *signal_received) { struct gc_arena gc = gc_new (); - struct sockaddr_in remote_verify = *remote; + //struct openvpn_sockaddr *remote = &act->dest; + struct openvpn_sockaddr remote_verify = act->dest; int new_sd = SOCKET_UNDEFINED; + CLEAR (*act); socket_do_listen (sd, local, do_listen, true); while (true) @@ -645,17 +656,17 @@ socket_listen_accept (socket_descriptor_t sd, continue; } - new_sd = socket_do_accept (sd, remote, nowait); + new_sd = socket_do_accept (sd, act, nowait); if (socket_defined (new_sd)) { update_remote (remote_dynamic, &remote_verify, remote_changed); if (addr_defined (&remote_verify) - && !addr_match (&remote_verify, remote)) + && !addr_match (&remote_verify, &act->dest)) { msg (M_WARN, "TCP NOTE: Rejected connection attempt from %s due to --remote setting", - print_sockaddr (remote, &gc)); + print_link_socket_actual (act, &gc)); if (openvpn_close_socket (new_sd)) msg (M_SOCKERR, "TCP: close socket failed (new_sd)"); } @@ -668,7 +679,7 @@ socket_listen_accept (socket_descriptor_t sd, if (!nowait && openvpn_close_socket (sd)) msg (M_SOCKERR, "TCP: close socket failed (sd)"); - tcp_connection_established (remote); + tcp_connection_established (act); gc_free (&gc); return new_sd; @@ -676,7 +687,7 @@ socket_listen_accept (socket_descriptor_t sd, static void socket_connect (socket_descriptor_t *sd, - struct sockaddr_in *remote, + struct openvpn_sockaddr *remote, struct remote_list *remote_list, const char *remote_dynamic, bool *remote_changed, @@ -689,8 +700,8 @@ socket_connect (socket_descriptor_t *sd, print_sockaddr (remote, &gc)); while (true) { - const int status = connect (*sd, (struct sockaddr *) remote, - sizeof (*remote)); + const int status = connect (*sd, (struct sockaddr *) &remote->sa, + sizeof (remote->sa)); get_signal (signal_received); if (*signal_received) @@ -711,7 +722,7 @@ socket_connect (socket_descriptor_t *sd, { remote_list_next (remote_list); remote_dynamic = remote_list_host (remote_list); - remote->sin_port = htons (remote_list_port (remote_list)); + remote->sa.sin_port = htons (remote_list_port (remote_list)); *remote_changed = true; } @@ -771,22 +782,22 @@ resolve_bind_local (struct link_socket *sock) /* resolve local address if undefined */ if (!addr_defined (&sock->info.lsa->local)) { - sock->info.lsa->local.sin_family = AF_INET; - sock->info.lsa->local.sin_addr.s_addr = + sock->info.lsa->local.sa.sin_family = AF_INET; + sock->info.lsa->local.sa.sin_addr.s_addr = (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, sock->local_host, 0, NULL, NULL) : htonl (INADDR_ANY)); - sock->info.lsa->local.sin_port = htons (sock->local_port); + sock->info.lsa->local.sa.sin_port = htons (sock->local_port); } /* bind to local address/port */ if (sock->bind_local) { - if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local, - sizeof (sock->info.lsa->local))) + if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local.sa, + sizeof (sock->info.lsa->local.sa))) { const int errnum = openvpn_errno_socket (); msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s", @@ -810,8 +821,8 @@ resolve_remote (struct link_socket *sock, /* resolve remote address if undefined */ if (!addr_defined (&sock->info.lsa->remote)) { - sock->info.lsa->remote.sin_family = AF_INET; - sock->info.lsa->remote.sin_addr.s_addr = 0; + sock->info.lsa->remote.sa.sin_family = AF_INET; + sock->info.lsa->remote.sa.sin_addr.s_addr = 0; if (sock->remote_host) { @@ -856,7 +867,7 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - sock->info.lsa->remote.sin_addr.s_addr = getaddr ( + sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr ( flags, sock->remote_host, retry, @@ -883,19 +894,22 @@ resolve_remote (struct link_socket *sock, } } - sock->info.lsa->remote.sin_port = htons (sock->remote_port); + sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port); } /* should we re-use previous active remote address? */ - if (addr_defined (&sock->info.lsa->actual)) + if (link_socket_actual_defined (&sock->info.lsa->actual)) { msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", - print_sockaddr (&sock->info.lsa->actual, &gc)); + print_link_socket_actual (&sock->info.lsa->actual, &gc)); if (remote_dynamic) *remote_dynamic = NULL; } else - sock->info.lsa->actual = sock->info.lsa->remote; + { + CLEAR (sock->info.lsa->actual); + sock->info.lsa->actual.dest = sock->info.lsa->remote; + } /* remember that we finished */ sock->did_resolve_remote = true; @@ -1162,7 +1176,7 @@ link_socket_init_phase2 (struct link_socket *sock, else if (sock->info.proto == PROTO_TCPv4_CLIENT) { socket_connect (&sock->sd, - &sock->info.lsa->actual, + &sock->info.lsa->actual.dest, sock->remote_list, remote_dynamic, &remote_changed, @@ -1200,7 +1214,7 @@ link_socket_init_phase2 (struct link_socket *sock, else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy) { socket_connect (&sock->ctrl_sd, - &sock->info.lsa->actual, + &sock->info.lsa->actual.dest, NULL, remote_dynamic, &remote_changed, @@ -1212,7 +1226,8 @@ link_socket_init_phase2 (struct link_socket *sock, establish_socks_proxy_udpassoc (sock->socks_proxy, sock->ctrl_sd, - sock->sd, &sock->socks_relay, + sock->sd, + &sock->socks_relay.dest, signal_received); if (*signal_received) @@ -1221,8 +1236,9 @@ link_socket_init_phase2 (struct link_socket *sock, sock->remote_host = sock->proxy_dest_host; sock->remote_port = sock->proxy_dest_port; sock->did_resolve_remote = false; - sock->info.lsa->actual.sin_addr.s_addr = 0; - sock->info.lsa->remote.sin_addr.s_addr = 0; + + sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0; + sock->info.lsa->remote.sa.sin_addr.s_addr = 0; resolve_remote (sock, 1, NULL, signal_received); @@ -1237,7 +1253,7 @@ link_socket_init_phase2 (struct link_socket *sock, if (remote_changed) { msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); - sock->info.lsa->remote.sin_addr.s_addr = sock->info.lsa->actual.sin_addr.s_addr; + sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr; } } @@ -1274,12 +1290,15 @@ link_socket_init_phase2 (struct link_socket *sock, msg (M_INFO, "%s link local%s: %s", proto2ascii (sock->info.proto, true), (sock->bind_local ? " (bound)" : ""), - print_sockaddr_ex (&sock->info.lsa->local, sock->bind_local, ":", &gc)); + print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); /* print active remote address */ msg (M_INFO, "%s link remote: %s", proto2ascii (sock->info.proto, true), - print_sockaddr_ex (&sock->info.lsa->actual, addr_defined (&sock->info.lsa->actual), ":", &gc)); + print_link_socket_actual_ex (&sock->info.lsa->actual, + ":", + PS_SHOW_PORT_IF_DEFINED, + &gc)); done: gc_free (&gc); @@ -1344,19 +1363,19 @@ socket_adjust_frame_parameters (struct frame *frame, int proto) void setenv_trusted (struct env_set *es, const struct link_socket_info *info) { - setenv_sockaddr (es, "trusted", &info->lsa->actual, SA_IP_PORT); + setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT); } void link_socket_connection_initiated (const struct buffer *buf, struct link_socket_info *info, - const struct sockaddr_in *addr, + const struct link_socket_actual *act, const char *common_name, struct env_set *es) { struct gc_arena gc = gc_new (); - info->lsa->actual = *addr; /* Note: skip this line for --force-dest */ + info->lsa->actual = *act; /* Note: skip this line for --force-dest */ setenv_trusted (es, info); info->connection_established = true; @@ -1365,7 +1384,7 @@ link_socket_connection_initiated (const struct buffer *buf, struct buffer out = alloc_buf_gc (256, &gc); if (common_name) buf_printf (&out, "[%s] ", common_name); - buf_printf (&out, "Peer Connection Initiated with %s", print_sockaddr (&info->lsa->actual, &gc)); + buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc)); msg (M_INFO, "%s", BSTR (&out)); } @@ -1375,7 +1394,7 @@ link_socket_connection_initiated (const struct buffer *buf, /* Process --ipchange plugin */ if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE)) { - const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, true, " ", &gc); + const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc); if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es)) msg (M_WARN, "WARNING: ipchange plugin call failed"); } @@ -1387,7 +1406,7 @@ link_socket_connection_initiated (const struct buffer *buf, setenv_str (es, "script_type", "ipchange"); buf_printf (&out, "%s %s", info->ipchange_command, - print_sockaddr_ex (&info->lsa->actual, true, " ", &gc)); + print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc)); system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed"); } @@ -1397,14 +1416,14 @@ link_socket_connection_initiated (const struct buffer *buf, void link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_info *info, - const struct sockaddr_in *from_addr) + const struct link_socket_actual *from_addr) { struct gc_arena gc = gc_new (); msg (D_LINK_ERRORS, "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", - print_sockaddr (from_addr, &gc), - (int)from_addr->sin_family, + print_link_socket_actual (from_addr, &gc), + (int)from_addr->dest.sa.sin_family, print_sockaddr (&info->lsa->remote, &gc)); buf->len = 0; @@ -1422,10 +1441,10 @@ link_socket_current_remote (const struct link_socket_info *info) { const struct link_socket_addr *lsa = info->lsa; - if (addr_defined (&lsa->actual)) - return ntohl (lsa->actual.sin_addr.s_addr); + if (link_socket_actual_defined (&lsa->actual)) + return ntohl (lsa->actual.dest.sa.sin_addr.s_addr); else if (addr_defined (&lsa->remote)) - return ntohl (lsa->remote.sin_addr.s_addr); + return ntohl (lsa->remote.sa.sin_addr.s_addr); else return 0; } @@ -1618,29 +1637,69 @@ socket_listen_event_handle (struct link_socket *s) */ const char * -print_sockaddr (const struct sockaddr_in *addr, struct gc_arena *gc) +print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc) { - return print_sockaddr_ex(addr, true, ":", gc); + return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); } const char * -print_sockaddr_ex (const struct sockaddr_in *addr, bool do_port, const char* separator, struct gc_arena *gc) +print_sockaddr_ex (const struct openvpn_sockaddr *addr, + const char* separator, + const unsigned int flags, + struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - const int port = ntohs (addr->sin_port); + if (addr) + { + struct buffer out = alloc_buf_gc (64, gc); + const int port = ntohs (addr->sa.sin_port); - mutex_lock_static (L_INET_NTOA); - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sin_addr) : "[undef]")); - mutex_unlock_static (L_INET_NTOA); + mutex_lock_static (L_INET_NTOA); + buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); + mutex_unlock_static (L_INET_NTOA); - if (do_port && port) - { - if (separator) - buf_printf (&out, "%s", separator); + if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) + && port) + { + if (separator) + buf_printf (&out, "%s", separator); - buf_printf (&out, "%d", port); + buf_printf (&out, "%d", port); + } + return BSTR (&out); } - return BSTR (&out); + else + return "[NULL]"; +} + +const char * +print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc) +{ + return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc); +} + +const char * +print_link_socket_actual_ex (const struct link_socket_actual *act, + const char *separator, + const unsigned int flags, + struct gc_arena *gc) +{ + if (act) + { + struct buffer out = alloc_buf_gc (128, gc); + buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc)); +#if ENABLE_IP_PKTINFO + if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr) + { + struct openvpn_sockaddr sa; + CLEAR (sa); + sa.sa.sin_addr = act->pi.ipi_spec_dst; + buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); + } +#endif + return BSTR (&out); + } + else + return "[NULL]"; } /* @@ -1667,7 +1726,7 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc) /* set environmental variables for ip/port in *addr */ void -setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct sockaddr_in *addr, const bool flags) +setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags) { char name_buf[256]; @@ -1677,13 +1736,13 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct socka openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); mutex_lock_static (L_INET_NTOA); - setenv_str (es, name_buf, inet_ntoa (addr->sin_addr)); + setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr)); mutex_unlock_static (L_INET_NTOA); - if ((flags & SA_IP_PORT) && addr->sin_port) + if ((flags & SA_IP_PORT) && addr->sa.sin_port) { openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); - setenv_int (es, name_buf, ntohs (addr->sin_port)); + setenv_int (es, name_buf, ntohs (addr->sa.sin_port)); } } @@ -1692,13 +1751,22 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c { if (addr || !(flags & SA_SET_IF_NONZERO)) { - struct sockaddr_in si; + struct openvpn_sockaddr si; CLEAR (si); - si.sin_addr.s_addr = htonl (addr); + si.sa.sin_addr.s_addr = htonl (addr); setenv_sockaddr (es, name_prefix, &si, flags); } } +void +setenv_link_socket_actual (struct env_set *es, + const char *name_prefix, + const struct link_socket_actual *act, + const bool flags) +{ + setenv_sockaddr (es, name_prefix, &act->dest, flags); +} + /* * Convert protocol names between index and ascii form. */ @@ -1828,19 +1896,72 @@ link_socket_read_tcp (struct link_socket *sock, #ifndef WIN32 +#if ENABLE_IP_PKTINFO + +struct openvpn_pktinfo +{ + struct cmsghdr cmsghdr; + struct in_pktinfo in_pktinfo; +}; + +static socklen_t +link_socket_read_udp_posix_recvmsg (struct link_socket *sock, + struct buffer *buf, + int maxsize, + struct link_socket_actual *from) +{ + struct iovec iov; + struct openvpn_pktinfo opi; + struct msghdr mesg; + socklen_t fromlen = sizeof (from->dest.sa); + + iov.iov_base = BPTR (buf); + iov.iov_len = maxsize; + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + mesg.msg_name = &from->dest.sa; + mesg.msg_namelen = fromlen; + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (opi); + 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 (opi)) + { + struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); + from->pi.ipi_ifindex = pkti->ipi_ifindex; + from->pi.ipi_spec_dst = pkti->ipi_spec_dst; + } + } + return fromlen; +} +#endif + int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from) + struct link_socket_actual *from) { - socklen_t fromlen = sizeof (*from); - CLEAR (*from); + socklen_t fromlen = sizeof (from->dest.sa); + from->dest.sa.sin_addr.s_addr = 0; ASSERT (buf_safe (buf, maxsize)); - buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, - (struct sockaddr *) from, &fromlen); - if (fromlen != sizeof (*from)) - bad_address_length (fromlen, sizeof (*from)); +#if ENABLE_IP_PKTINFO + if (sock->sockflags & SF_USE_IP_PKTINFO) + fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); + else +#endif + buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, + (struct sockaddr *) &from->dest.sa, &fromlen); + if (fromlen != sizeof (from->dest.sa)) + bad_address_length (fromlen, sizeof (from->dest.sa)); return buf->len; } @@ -1853,7 +1974,7 @@ link_socket_read_udp_posix (struct link_socket *sock, int link_socket_write_tcp (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct link_socket_actual *to) { packet_size_type len = BLEN (buf); dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset); @@ -1867,6 +1988,41 @@ link_socket_write_tcp (struct link_socket *sock, #endif } +#if ENABLE_IP_PKTINFO + +int +link_socket_write_udp_posix_sendmsg (struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) +{ + struct iovec iov; + struct msghdr mesg; + struct cmsghdr *cmsg; + struct in_pktinfo *pkti; + struct openvpn_pktinfo opi; + + iov.iov_base = BPTR (buf); + iov.iov_len = BLEN (buf); + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + mesg.msg_name = &to->dest.sa; + mesg.msg_namelen = sizeof (to->dest.sa); + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (opi); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = sizeof (opi); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); + pkti->ipi_ifindex = to->pi.ipi_ifindex; + pkti->ipi_spec_dst = to->pi.ipi_spec_dst; + pkti->ipi_addr.s_addr = 0; + return sendmsg (sock->sd, &mesg, 0); +} + +#endif + /* * Win32 overlapped socket I/O functions. */ @@ -1981,7 +2137,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize) } int -socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct sockaddr_in *to) +socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to) { if (sock->writes.iostate == IOSTATE_INITIAL) { @@ -2005,7 +2161,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so { /* set destination address for UDP writes */ sock->writes.addr_defined = true; - sock->writes.addr = *to; + sock->writes.addr = to->dest.sa; sock->writes.addrlen = sizeof (sock->writes.addr); status = WSASendTo( @@ -2081,11 +2237,10 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so } int -socket_finalize ( - SOCKET s, +socket_finalize (SOCKET s, struct overlapped_io *io, struct buffer *buf, - struct sockaddr_in *from) + struct link_socket_actual *from) { int ret = -1; BOOL status; @@ -2162,10 +2317,10 @@ socket_finalize ( { if (io->addrlen != sizeof (io->addr)) bad_address_length (io->addrlen, sizeof (io->addr)); - *from = io->addr; + from->dest.sa = io->addr; } else - CLEAR (*from); + CLEAR (from->dest.sa); } if (buf) |