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;
}
Beispiel #3
0
/*
 * 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;
}
Beispiel #7
0
/* 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;
}
Beispiel #8
0
/* 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;
}
Beispiel #9
0
/* 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;
}
Beispiel #10
0
/* 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;
}