void ssh_virtual_adapter_ip_ether_address(SshIpAddr ip, unsigned char *buffer) { memset(buffer, 0, SSH_ETHERH_ADDRLEN); if (SSH_IP_IS4(ip)) { buffer[1] = 2; SSH_IP4_ENCODE(ip, buffer + 2); } #if defined (WITH_IPV6) else { SshUInt32 value; value = SSH_IP6_WORD0_TO_INT(ip); value ^= SSH_IP6_WORD1_TO_INT(ip); value ^= SSH_IP6_WORD2_TO_INT(ip); value ^= SSH_IP6_WORD3_TO_INT(ip); buffer[1] = 2; SSH_PUT_32BIT(buffer + 2, value); } #endif /* WITH_IPV6 */ }
static Boolean ssh_ip_route_lookup_ipv4( SshIpAddr destination, DWORD *ifindex, SshIpAddr nexthop, DWORD *mtu) { DWORD d, error; MIB_IPFORWARDROW ifr; SSH_IP4_ENCODE(destination, &d); error = GetBestRoute(d, 0, &ifr); if (error != NO_ERROR) { if (error == ERROR_CAN_NOT_COMPLETE) { SSH_DEBUG(SSH_D_LOWOK, ("No route found")); return FALSE; } else { SSH_DEBUG(SSH_D_FAIL, ("GetBestRoute: error 0x%08X", (unsigned)error)); return FALSE; } } /* Do not consider local routes via loopback interfaces. */ if (ifr.dwForwardProto == MIB_IPPROTO_LOCAL && (ifr.dwForwardDest & ifr.dwForwardMask) != (ifr.dwForwardNextHop & ifr.dwForwardMask)) { SSH_DEBUG(SSH_D_LOWOK, ("Ignoring loopback route")); return FALSE; } *ifindex = ifr.dwForwardIfIndex; /* For directly connected destinatinations report the destination as the next hop. */ if (ifr.dwForwardType == MIB_IPROUTE_TYPE_DIRECT) SSH_IP4_DECODE(nexthop, &d); else SSH_IP4_DECODE(nexthop, &ifr.dwForwardNextHop); /* No route MTU; use link MTU. */ *mtu = 0; return TRUE; }
/* * Make socks reply packet that can be sent to client and store it to buffer. * If connection is granted set command_code to SSH_SOCKS_REPLY_GRANTED, * otherwise set it to some error code (SSH_SOCKS_REPLY_FAILED_*). * The port and ip from the socksinfo are sent along with reply and if * the request that was granted was bind they should indicate the port and ip * address of the other end of the socket. * Does NOT free the SocksInfo structure. */ SocksError ssh_socks4_server_generate_reply(SshBuffer buffer, SocksInfo socksinfo) { unsigned char *data; int port; SshIpAddrStruct ip_addr; port = ssh_inet_get_port_by_service(socksinfo->port, ssh_custr("tcp")); if (port >= 65536 || port <= 0) return SSH_SOCKS_ERROR_INVALID_ARGUMENT; if (!ssh_ipaddr_parse(&ip_addr, socksinfo->ip)) { SSH_DEBUG(2, ("Couldn't parse IP-address `%s'.", socksinfo->ip)); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } /* nowadays the ip-addresses returned by ssh functions is more and more often in ipv6 format (ipv4 addresses are in ipv6 mapped ipv4 format). */ ssh_inet_convert_ip6_mapped_ip4_to_ip4(&ip_addr); if (!SSH_IP_IS4(&ip_addr)) { SSH_DEBUG(2, ("IP-address `%s' isn't an IPv4 numerical address.", socksinfo->ip)); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (ssh_buffer_append_space(buffer, &data, SOCKS4_REPLY_SIZE) != SSH_BUFFER_OK) { SSH_DEBUG(2, ("Failed to allocate reply buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } *data++ = 0; /* SOCKS4 replys must have version number '0'. */ *data++ = socksinfo->command_code; SSH_PUT_16BIT(data, port); data += 2; SSH_IP4_ENCODE(&ip_addr, data); return SSH_SOCKS_SUCCESS; }
SshOperationHandle ssh_pm_cfgmode_client_store_register(SshPm pm, SshPmTunnel tunnel, SshPmActiveCfgModeClient client, SshIpAddr address, void *address_context, SshPmRemoteAccessAttrsFreeCB free_cb, void *free_cb_context, SshPmStatusCB status_cb, void *status_cb_context) { SSH_DEBUG(SSH_D_LOWOK, ("Registering address `%@'", ssh_ipaddr_render, address)); SSH_ASSERT(client->status_cb == NULL_FNPTR); if (client->flags & SSH_PM_CFGMODE_CLIENT_ADDING_ARP) goto error; if (!SSH_IP_DEFINED(address)) goto error; if (SSH_IP_IS4(address)) { SSH_ASSERT(client->ip4 == NULL); client->ip4 = ssh_memdup(address, sizeof(*address)); if (client->ip4 == NULL) goto error; client->ip4_address_context = address_context; } else { SSH_ASSERT(client->ip6 == NULL); client->ip6 = ssh_memdup(address, sizeof(*address)); if (client->ip6 == NULL) goto error; client->ip6_address_context = address_context; } client->free_cb = free_cb; client->free_cb_context = free_cb_context; /* Check if we should add a proxy ARP entry for the remote access client. */ if (tunnel->flags & SSH_PM_TR_PROXY_ARP) { unsigned char media_addr[SSH_ETHERH_ADDRLEN]; SshUInt32 flags; /* Create a fake ethernet address. */ memset(media_addr, 0, sizeof(media_addr)); if (SSH_IP_IS4(address)) { media_addr[1] = 2; SSH_IP4_ENCODE(address, media_addr + 2); client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_PROXY_ARP; } else { SshUInt32 value; value = SSH_IP6_WORD0_TO_INT(address); value ^= SSH_IP6_WORD1_TO_INT(address); value ^= SSH_IP6_WORD2_TO_INT(address); value ^= SSH_IP6_WORD3_TO_INT(address); media_addr[1] = 2; SSH_PUT_32BIT(media_addr + 2, value); client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_PROXY_ARP; } /* Flags for ARP entry. */ flags = SSH_PME_ARP_PERMANENT | SSH_PME_ARP_GLOBAL | SSH_PME_ARP_PROXY; /* Store status_cb. */ client->status_cb = status_cb; client->status_cb_context = status_cb_context; if (SSH_IP_IS4(address)) client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_REGISTERING; else client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_REGISTERING; /* Register an abort callback for the engine operation. */ ssh_operation_register_no_alloc(&client->operation, pm_cfgmode_client_store_arp_abort, client); /* Take a reference to the client and mark ARP ongoing. */ ssh_pm_cfgmode_client_store_take_reference(pm, client); client->flags |= SSH_PM_CFGMODE_CLIENT_ADDING_ARP; /* Add ARP entry. */ SSH_DEBUG(SSH_D_LOWSTART, ("Adding ARP entry")); ssh_pme_arp_add(pm->engine, address, 0, media_addr, sizeof(media_addr), flags, pm_cfgmode_client_store_arp_cb, client); return &client->operation; } if (status_cb) (*status_cb)(pm, TRUE, status_cb_context); return NULL; error: if (status_cb) (*status_cb)(pm, FALSE, status_cb_context); return NULL; }
static Boolean ssh_ip_route_remove_ipv4(SshIpAddr prefix, SshIpAddr nexthop) { Boolean ok = FALSE; MIB_IPFORWARDTABLE *ift = NULL; MIB_IPFORWARDROW *ifr, the_ifr; DWORD error; unsigned int i; /* Get route table. */ if (!(ift = ssh_ip_route_get_ipforwardtable())) goto end; /* Set up route destination, mask and next hop. */ memset(&the_ifr, 0, sizeof the_ifr); SSH_IP4_ENCODE(prefix, &the_ifr.dwForwardDest); if (prefix->mask_len >= 32) the_ifr.dwForwardMask = 0xFFFFFFFFU; else SSH_PUT_32BIT(&the_ifr.dwForwardMask, ~(0xFFFFFFFFU >> prefix->mask_len)); SSH_IP4_ENCODE(nexthop, &the_ifr.dwForwardNextHop); /* Find the route. Set route interface and type. */ for (i = 0; i < (int)ift->dwNumEntries; i++) { ifr = &ift->table[i]; if (ifr->dwForwardDest == the_ifr.dwForwardDest && ifr->dwForwardMask == the_ifr.dwForwardMask && ifr->dwForwardNextHop == the_ifr.dwForwardNextHop) { the_ifr.dwForwardIfIndex = ifr->dwForwardIfIndex; the_ifr.dwForwardType = ifr->dwForwardType; break; } } if (i >= (int)ift->dwNumEntries) { SSH_DEBUG(SSH_D_FAIL, ("Route not found")); goto end; } /* Delete row. */ error = DeleteIpForwardEntry(&the_ifr); if (error != NO_ERROR) { SSH_DEBUG(SSH_D_FAIL, ("DeleteIpForwardEntry: error 0x%08X", (unsigned)error)); goto end; } ok = TRUE; end: if (ift) ssh_free(ift); return ok; }
static Boolean ssh_ip_route_add_ipv4(SshIpAddr prefix, SshIpAddr nexthop) { Boolean ok = FALSE; MIB_IPADDRTABLE *iat = NULL; MIB_IPADDRROW *iar; MIB_IPFORWARDTABLE *ift = NULL; MIB_IPFORWARDROW *ifr, new_ifr; DWORD error; unsigned int i, j; /* Get the table of local IP addresses and the route table. */ if (!(iat = ssh_ip_route_get_ipaddrtable()) || !(ift = ssh_ip_route_get_ipforwardtable())) goto end; /* Set up route destination, mask and next hop. */ memset(&new_ifr, 0, sizeof new_ifr); SSH_IP4_ENCODE(prefix, &new_ifr.dwForwardDest); if (prefix->mask_len >= 32) new_ifr.dwForwardMask = 0xFFFFFFFFU; else SSH_PUT_32BIT(&new_ifr.dwForwardMask, ~(0xFFFFFFFFU >> prefix->mask_len)); SSH_IP4_ENCODE(nexthop, &new_ifr.dwForwardNextHop); /* Find a local IP address that a) either is the next hop or belongs to the same network as the next hop and b) is up, i.e. has a local route in the routing table. Set route interface and type. */ for (i = 0; i < (int)iat->dwNumEntries; i++) { iar = &iat->table[i]; SSH_DEBUG(SSH_D_NICETOKNOW, ("Matching nexthop %@ with interface address %@/%@", ssh_ip_route_render_ipv4, &new_ifr.dwForwardNextHop, ssh_ip_route_render_ipv4, &iar->dwAddr, ssh_ip_route_render_ipv4, &iar->dwMask)); /* Check L2 connectivity. */ if (iar->dwAddr == new_ifr.dwForwardNextHop) { new_ifr.dwForwardIfIndex = iar->dwIndex; new_ifr.dwForwardType = MIB_IPROUTE_TYPE_DIRECT; } else if ((iar->dwAddr & iar->dwMask) == (new_ifr.dwForwardNextHop & iar->dwMask)) { new_ifr.dwForwardIfIndex = iar->dwIndex; new_ifr.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; } else { continue; } SSH_DEBUG(SSH_D_NICETOKNOW, ("Nexthop %@ is connected with interface address %@", ssh_ip_route_render_ipv4, &new_ifr.dwForwardNextHop, ssh_ip_route_render_ipv4, &iar->dwAddr)); /* Find a local route for the local address. */ for (j = 0; j < (int)ift->dwNumEntries; j++) { ifr = &ift->table[j]; if (ifr->dwForwardProto == PROTO_IP_LOCAL && ifr->dwForwardDest == iar->dwAddr) break; } if (j < (int)ift->dwNumEntries) break; SSH_DEBUG( SSH_D_NICETOKNOW, ("No local route found for interface address %@", ssh_ip_route_render_ipv4, &iar->dwAddr)); } if (i >= (int)iat->dwNumEntries) { SSH_DEBUG(SSH_D_FAIL, ("Next hop is not directly connected")); goto end; } /* Set the rest of route data. */ new_ifr.dwForwardProto = PROTO_IP_NETMGMT; new_ifr.dwForwardMetric1 = 1; new_ifr.dwForwardMetric2 = MIB_IPROUTE_METRIC_UNUSED; new_ifr.dwForwardMetric3 = MIB_IPROUTE_METRIC_UNUSED; new_ifr.dwForwardMetric4 = MIB_IPROUTE_METRIC_UNUSED; new_ifr.dwForwardMetric5 = MIB_IPROUTE_METRIC_UNUSED; /* Add row. */ error = CreateIpForwardEntry(&new_ifr); if (error != NO_ERROR) { SSH_DEBUG(SSH_D_FAIL, ("CreateIpForwardEntry: error 0x%08X", (unsigned)error)); goto end; } ok = TRUE; end: if (ift) ssh_free(ift); if (iat) ssh_free(iat); return ok; }
/* Perform route lookup using linux ip_route_input. The route lookup will use the following selectors: dst, src, inbound ifnum, ip protocol, tos, and fwmark. The source address is expected to be non-local and it must be defined. The following selectors are ignored: dst port, src port, icmp type, icmp code, ipsec spi. */ Boolean ssh_interceptor_route_input_ipv4(SshInterceptor interceptor, SshInterceptorRouteKey key, SshUInt16 selector, SshInterceptorRouteResult result) { u32 daddr, saddr; u8 ipproto; u8 tos; u32 fwmark; struct sk_buff *skbp; struct net_device *dev; struct rtable *rt; int rval = 0; u16 rt_type; struct iphdr *iph = NULL; #ifdef DEBUG_LIGHT unsigned char *rt_type_str; #endif /* DEBUG_LIGHT */ SSH_INTERCEPTOR_STACK_MARK(); SSH_IP4_ENCODE(&key->dst, (unsigned char *) &daddr); /* Initialize */ saddr = 0; ipproto = 0; tos = 0; fwmark = 0; dev = NULL; if (selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) SSH_IP4_ENCODE(&key->src, (unsigned char *) &saddr); if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IN_IFNUM) { SSH_LINUX_ASSERT_VALID_IFNUM(key->ifnum); dev = ssh_interceptor_ifnum_to_netdev(interceptor, key->ifnum); } if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO) ipproto = key->ipproto; if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS) tos = key->nh.ip4.tos; #if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) #ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR /* Use linux fw_mark in routing */ if (selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION) fwmark = key->extension[SSH_LINUX_FWMARK_EXTENSION_SELECTOR]; #endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */ #endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */ /* Build dummy skb */ skbp = alloc_skb(SSH_IPH4_HDRLEN, GFP_ATOMIC); if (skbp == NULL) goto fail; SSH_SKB_RESET_MACHDR(skbp); iph = (struct iphdr *) skb_put(skbp, SSH_IPH4_HDRLEN); if (iph == NULL) { dev_kfree_skb(skbp); goto fail; } SSH_SKB_SET_NETHDR(skbp, (unsigned char *) iph); skb_dst_set(skbp, NULL); skbp->protocol = __constant_htons(ETH_P_IP); SSH_SKB_MARK(skbp) = fwmark; iph->protocol = ipproto; SSH_DEBUG(SSH_D_LOWOK, ("Route lookup: " "dst %@ src %@ ifnum %d[%s] ipproto %d tos 0x%02x fwmark 0x%x", ssh_ipaddr_render, &key->dst, ssh_ipaddr_render, ((selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) ? &key->src : NULL), (dev ? dev->ifindex : -1), (dev ? dev->name : "none"), ipproto, tos, fwmark)); /* Perform route lookup */ rval = ip_route_input(skbp, daddr, saddr, tos, dev); if (rval < 0 || skb_dst(skbp) == NULL) { dev_kfree_skb(skbp); goto fail; } /* Get the gateway, mtu and ifnum */ rt = (struct rtable *) skb_dst(skbp); SSH_IP4_DECODE(result->gw, &rt->rt_gateway); result->mtu = SSH_LINUX_DST_MTU(skb_dst(skbp)); result->ifnum = skb_dst(skbp)->dev->ifindex; rt_type = rt->rt_type; #ifdef DEBUG_LIGHT switch (rt_type) { case RTN_UNSPEC: rt_type_str = "unspec"; break; case RTN_UNICAST: rt_type_str = "unicast"; break; case RTN_LOCAL: rt_type_str = "local"; break; case RTN_BROADCAST: rt_type_str = "broadcast"; break; case RTN_ANYCAST: rt_type_str = "anycast"; break; case RTN_MULTICAST: rt_type_str = "multicast"; break; case RTN_BLACKHOLE: rt_type_str = "blackhole"; break; case RTN_UNREACHABLE: rt_type_str = "unreachable"; break; case RTN_PROHIBIT: rt_type_str = "prohibit"; break; case RTN_THROW: rt_type_str = "throw"; break; case RTN_NAT: rt_type_str = "nat"; break; case RTN_XRESOLVE: rt_type_str = "xresolve"; break; default: rt_type_str = "unknown"; } #endif /* DEBUG_LIGHT */ SSH_DEBUG(SSH_D_LOWOK, ("Route result: dst %@ via %@ ifnum %d[%s] mtu %d type %s [%d]", ssh_ipaddr_render, &key->dst, ssh_ipaddr_render, result->gw, result->ifnum, (rt->u.dst.dev->name ? rt->u.dst.dev->name : "none"), result->mtu, rt_type_str, rt_type)); #ifdef SSH_IPSEC_IP_ONLY_INTERCEPTOR #ifdef LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING /* Check if need to create a child dst_entry with interface MTU. */ if ((selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_TRANSFORM_APPLIED) && skb_dst(skbp)->child == NULL) { if (interceptor_route_create_child_dst(skb_dst(skbp)) == NULL) SSH_DEBUG(SSH_D_FAIL, ("Could not create child dst_entry for dst %p", skb_dst(skbp))); } #endif /* LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING */ #endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */ /* Release the routing table entry ; otherwise a memory leak occurs in the route entry table. */ dst_release(skb_dst(skbp)); skb_dst_set(skbp, NULL); dev_kfree_skb(skbp); /* Assert that ifnum fits into the SshInterceptorIfnum data type. */ SSH_LINUX_ASSERT_IFNUM(result->ifnum); /* Check that ifnum does not collide with SSH_INTERCEPTOR_INVALID_IFNUM. */ if (result->ifnum == SSH_INTERCEPTOR_INVALID_IFNUM) goto fail; /* Accept only unicast, broadcast, anycast, multicast and local routes. */ if (rt_type == RTN_UNICAST || rt_type == RTN_BROADCAST || rt_type == RTN_ANYCAST || rt_type == RTN_MULTICAST || rt_type == RTN_LOCAL) { ssh_interceptor_release_netdev(dev); SSH_LINUX_ASSERT_VALID_IFNUM(result->ifnum); return TRUE; } /* Fail route lookup for other route types. */ fail: if (dev) ssh_interceptor_release_netdev(dev); SSH_DEBUG(SSH_D_FAIL, ("Route lookup for %@ failed with code %d", ssh_ipaddr_render, &key->dst, rval)); return FALSE; }
/* Perform route lookup using linux ip_route_output_key. The route lookup will use the following selectors: dst, src, outbound ifnum, ip protocol, tos, and fwmark. The source address is expected to be local or undefined. The following selectors are ignored: dst port, src port, icmp type, icmp code, ipsec spi. */ Boolean ssh_interceptor_route_output_ipv4(SshInterceptor interceptor, SshInterceptorRouteKey key, SshUInt16 selector, SshInterceptorRouteResult result) { u32 daddr; struct rtable *rt; int rval; struct flowi rt_key; u16 rt_type; #ifdef DEBUG_LIGHT unsigned char *rt_type_str; u32 fwmark = 0; #endif /* DEBUG_LIGHT */ SSH_INTERCEPTOR_STACK_MARK(); SSH_IP4_ENCODE(&key->dst, (unsigned char *) &daddr); /* Initialize rt_key with zero values */ memset(&rt_key, 0, sizeof(rt_key)); rt_key.fl4_dst = daddr; if (selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) SSH_IP4_ENCODE(&key->src, (unsigned char *) &rt_key.fl4_src); if (selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM) { SSH_LINUX_ASSERT_VALID_IFNUM(key->ifnum); rt_key.oif = key->ifnum; } if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO) rt_key.proto = key->ipproto; if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS) rt_key.fl4_tos = key->nh.ip4.tos; rt_key.fl4_scope = RT_SCOPE_UNIVERSE; #if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) #ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR /* Use linux fw_mark in routing */ if (selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION) { #ifdef LINUX_HAS_SKB_MARK rt_key.mark = key->extension[SSH_LINUX_FWMARK_EXTENSION_SELECTOR]; #else /* LINUX_HAS_SKB_MARK */ #ifdef CONFIG_IP_ROUTE_FWMARK rt_key.fl4_fwmark = key->extension[SSH_LINUX_FWMARK_EXTENSION_SELECTOR]; #endif /* CONFIG_IP_ROUTE_FWMARK */ #endif /* LINUX_HAS_SKB_MARK */ #ifdef DEBUG_LIGHT fwmark = key->extension[SSH_LINUX_FWMARK_EXTENSION_SELECTOR]; #endif /* DEBUG_LIGHT */ } #endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */ #endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */ SSH_DEBUG(SSH_D_LOWOK, ("Route lookup: " "dst %@ src %@ ifnum %d ipproto %d tos 0x%02x fwmark 0x%x", ssh_ipaddr_render, &key->dst, ssh_ipaddr_render, ((selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) ? &key->src : NULL), ((selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM) ? key->ifnum : -1), ((selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO) ? key->ipproto : -1), ((selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS) ? key->nh.ip4.tos : 0), ((selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION) ? fwmark : 0))); /* Perform route lookup */ #ifdef LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT rval = ip_route_output_key(&init_net, &rt, &rt_key); #else /* LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */ rval = ip_route_output_key(&rt, &rt_key); #endif /* LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */ if (rval < 0) { goto fail; } /* Get the gateway, mtu and ifnum */ SSH_IP4_DECODE(result->gw, &rt->rt_gateway); result->mtu = SSH_LINUX_DST_MTU(&rt->u.dst); result->ifnum = rt->u.dst.dev->ifindex; rt_type = rt->rt_type; #ifdef DEBUG_LIGHT switch (rt_type) { case RTN_UNSPEC: rt_type_str = "unspec"; break; case RTN_UNICAST: rt_type_str = "unicast"; break; case RTN_LOCAL: rt_type_str = "local"; break; case RTN_BROADCAST: rt_type_str = "broadcast"; break; case RTN_ANYCAST: rt_type_str = "anycast"; break; case RTN_MULTICAST: rt_type_str = "multicast"; break; case RTN_BLACKHOLE: rt_type_str = "blackhole"; break; case RTN_UNREACHABLE: rt_type_str = "unreachable"; break; case RTN_PROHIBIT: rt_type_str = "prohibit"; break; case RTN_THROW: rt_type_str = "throw"; break; case RTN_NAT: rt_type_str = "nat"; break; case RTN_XRESOLVE: rt_type_str = "xresolve"; break; default: rt_type_str = "unknown"; } #endif /* DEBUG_LIGHT */ SSH_DEBUG(SSH_D_LOWOK, ("Route result: dst %@ via %@ ifnum %d[%s] mtu %d type %s [%d]", ssh_ipaddr_render, &key->dst, ssh_ipaddr_render, result->gw, result->ifnum, (rt->u.dst.dev->name ? rt->u.dst.dev->name : "none"), result->mtu, rt_type_str, rt_type)); #ifdef SSH_IPSEC_IP_ONLY_INTERCEPTOR #ifdef LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING /* Check if need to create a child dst_entry with interface MTU. */ if ((selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_TRANSFORM_APPLIED) && rt->u.dst.child == NULL) { if (interceptor_route_create_child_dst(&rt->u.dst) == NULL) SSH_DEBUG(SSH_D_FAIL, ("Could not create child dst_entry for dst %p", &rt->u.dst)); } #endif /* LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING */ #endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */ /* Release the routing table entry ; otherwise a memory leak occurs in the route entry table. */ ip_rt_put(rt); /* Assert that ifnum fits into the SshInterceptorIfnum data type. */ SSH_LINUX_ASSERT_IFNUM(result->ifnum); /* Check that ifnum does not collide with SSH_INTERCEPTOR_INVALID_IFNUM. */ if (result->ifnum == SSH_INTERCEPTOR_INVALID_IFNUM) goto fail; /* Accept only unicast, broadcast, anycast, multicast and local routes */ if (rt_type == RTN_UNICAST || rt_type == RTN_BROADCAST || rt_type == RTN_ANYCAST || rt_type == RTN_MULTICAST || rt_type == RTN_LOCAL) { SSH_LINUX_ASSERT_VALID_IFNUM(result->ifnum); return TRUE; } fail: /* Fail route lookup for other route types */ SSH_DEBUG(SSH_D_FAIL, ("Route lookup for %@ failed with code %d", ssh_ipaddr_render, &key->dst, rval)); return FALSE; }
/* For SOCKS5. */ SocksError ssh_socks5_client_generate_open(SshBuffer buffer, SocksInfo socksinfo) { unsigned char *data; unsigned long port; size_t bytes = 0L, bytes_needed = 0; SshIpAddrStruct ip_addr; unsigned int address_type; port = ssh_inet_get_port_by_service(socksinfo->port, ssh_custr("tcp")); if (port >= 65536 || port <= 0) return SSH_SOCKS_ERROR_INVALID_ARGUMENT; if (ssh_ipaddr_parse(&ip_addr, socksinfo->ip)) { if (SSH_IP_IS4(&ip_addr)) address_type = SSH_SOCKS5_ATYP_IPV4; else address_type = SSH_SOCKS5_ATYP_IPV6; } else { SSH_DEBUG(2, ("IP `%s' could not be parsed, assuming it is a hostname.", socksinfo->ip)); address_type = SSH_SOCKS5_ATYP_FQDN; } bytes = ssh_encode_buffer(buffer, SSH_ENCODE_CHAR(socksinfo->socks_version_number), SSH_ENCODE_CHAR(socksinfo->command_code), /* RSV. */ SSH_ENCODE_CHAR(0), SSH_ENCODE_CHAR(address_type), SSH_FORMAT_END); if (bytes == 0) { SSH_DEBUG(2, ("Encoding command buffer failed.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (address_type == SSH_SOCKS5_ATYP_IPV4) bytes_needed = 4; else if (address_type == SSH_SOCKS5_ATYP_IPV6) bytes_needed = 16; else if (address_type == SSH_SOCKS5_ATYP_FQDN) /* length field + address length */ bytes_needed = 1 + ssh_ustrlen(socksinfo->ip); /* port */ bytes_needed += 2; /* Allocate space for the IP-address*/ if (ssh_buffer_append_space(buffer, &data, bytes_needed) != SSH_BUFFER_OK) { SSH_DEBUG(2, ("Allocating space for the IP-address failed.")); ssh_buffer_consume_end(buffer, bytes); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (address_type == SSH_SOCKS5_ATYP_IPV4) { SSH_IP4_ENCODE(&ip_addr, data); } else if (address_type == SSH_SOCKS5_ATYP_IPV6) { SSH_IP6_ENCODE(&ip_addr, data); } else if (address_type == SSH_SOCKS5_ATYP_FQDN) { *data = ssh_ustrlen(socksinfo->ip); ssh_ustrcpy(data + 1, socksinfo->ip); } bytes += bytes_needed - 2; data += bytes_needed - 2; SSH_PUT_16BIT(data, port); SSH_DEBUG(4, ("Command buffer size %zd.", bytes + bytes_needed)); return SSH_SOCKS_SUCCESS; }
/* For SOCKS4. */ SocksError ssh_socks4_client_generate_open(SshBuffer buffer, SocksInfo socksinfo) { unsigned char *data; const unsigned char *username; unsigned long port; size_t bytes = 0L, ret = 0; SshIpAddrStruct ip_addr; port = ssh_inet_get_port_by_service(socksinfo->port, ssh_custr("tcp")); if (port >= 65536 || port <= 0) return SSH_SOCKS_ERROR_INVALID_ARGUMENT; if (socksinfo->username == NULL) username = ssh_custr(""); else username = socksinfo->username; if (ssh_ustrlen(username) > SOCKS4_MAX_NAME_LEN) return SSH_SOCKS_ERROR_INVALID_ARGUMENT; if (!ssh_ipaddr_parse(&ip_addr, socksinfo->ip)) { SSH_DEBUG(2, ("IP `%s' could not be parsed.", socksinfo->ip)); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } /* nowadays the ip-addresses returned by ssh functions is more and more often in ipv6 format (ipv4 addresses are in ipv6 mapped ipv4 format). */ ssh_inet_convert_ip6_mapped_ip4_to_ip4(&ip_addr); if (!SSH_IP_IS4(&ip_addr)) { SSH_DEBUG(2, ("IP `%s' is not a valid IPv4 address.", socksinfo->ip)); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } bytes = ssh_encode_buffer(buffer, SSH_ENCODE_CHAR(socksinfo->socks_version_number), SSH_ENCODE_CHAR(socksinfo->command_code), SSH_ENCODE_CHAR((port & 0xff00U) >> 8), SSH_ENCODE_CHAR(port & 0xffU), SSH_FORMAT_END); if (bytes == 0) { SSH_DEBUG(2, ("Encoding command buffer failed.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } /* Allocate space for the IP-address*/ if (ssh_buffer_append_space(buffer, &data, 4) != SSH_BUFFER_OK) { SSH_DEBUG(2, ("Allocating space for the IP-address failed.")); ssh_buffer_consume_end(buffer, bytes); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } SSH_IP4_ENCODE(&ip_addr, data); data += 4; bytes += 4; ret = ssh_encode_buffer(buffer, SSH_ENCODE_DATA(username, ssh_ustrlen(username)), SSH_ENCODE_DATA(ssh_custr("\0"), 1), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Encoding username to the command buffer failed.")); ssh_buffer_consume_end(buffer, bytes); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } SSH_DEBUG(4, ("Command buffer size %zd.", bytes + ret)); return SSH_SOCKS_SUCCESS; }