aboutsummaryrefslogtreecommitdiff
path: root/src/exit/gnunet-daemon-exit.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-21 22:30:54 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-21 22:30:54 +0000
commit0ac5d4626b676bbccebb1c67a2963277ebf2bc00 (patch)
tree00394b8779638e45a5b9968c4dfdba7d9e83256c /src/exit/gnunet-daemon-exit.c
parentc5dc23a6f2cfd4cff8cb13fa50614816dd480843 (diff)
downloadgnunet-0ac5d4626b676bbccebb1c67a2963277ebf2bc00.tar.gz
gnunet-0ac5d4626b676bbccebb1c67a2963277ebf2bc00.zip
-implementing ICMP PT and generation if ICMP payloads on EXIT->TUN link (for both service and Internet exit)
Diffstat (limited to 'src/exit/gnunet-daemon-exit.c')
-rw-r--r--src/exit/gnunet-daemon-exit.c358
1 files changed, 336 insertions, 22 deletions
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c
index f55106243..514554b80 100644
--- a/src/exit/gnunet-daemon-exit.c
+++ b/src/exit/gnunet-daemon-exit.c
@@ -390,6 +390,12 @@ get_redirect_state (int af,
390 GNUNET_HashCode key; 390 GNUNET_HashCode key;
391 struct TunnelState *state; 391 struct TunnelState *state;
392 392
393 if (protocol == IPPROTO_ICMP)
394 {
395 /* ignore ports */
396 destination_port = 0;
397 local_port = 0;
398 }
393 ri.remote_address.af = af; 399 ri.remote_address.af = af;
394 if (af == AF_INET) 400 if (af == AF_INET)
395 ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip); 401 ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip);
@@ -1858,6 +1864,58 @@ send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
1858 1864
1859 1865
1860/** 1866/**
1867 * Synthesize a plausible ICMP payload for an ICMPv4 error
1868 * response on the given tunnel.
1869 *
1870 * @param state tunnel information
1871 * @param ipp IPv6 header to fill in (ICMP payload)
1872 * @param udp "UDP" header to fill in (ICMP payload); might actually
1873 * also be the first 8 bytes of the TCP header
1874 */
1875static void
1876make_up_icmpv4_payload (struct TunnelState *state,
1877 struct GNUNET_TUN_IPv4Header *ipp,
1878 struct GNUNET_TUN_UdpHeader *udp)
1879{
1880 GNUNET_TUN_initialize_ipv4_header (ipp,
1881 state->ri.remote_address.proto,
1882 sizeof (struct GNUNET_TUN_TcpHeader),
1883 &state->ri.remote_address.address.ipv4,
1884 &state->ri.local_address.address.ipv4);
1885 udp->spt = htons (state->ri.remote_address.port);
1886 udp->dpt = htons (state->ri.local_address.port);
1887 udp->len = htons (0);
1888 udp->crc = htons (0);
1889}
1890
1891
1892/**
1893 * Synthesize a plausible ICMP payload for an ICMPv6 error
1894 * response on the given tunnel.
1895 *
1896 * @param state tunnel information
1897 * @param ipp IPv6 header to fill in (ICMP payload)
1898 * @param udp "UDP" header to fill in (ICMP payload); might actually
1899 * also be the first 8 bytes of the TCP header
1900 */
1901static void
1902make_up_icmpv6_payload (struct TunnelState *state,
1903 struct GNUNET_TUN_IPv6Header *ipp,
1904 struct GNUNET_TUN_UdpHeader *udp)
1905{
1906 GNUNET_TUN_initialize_ipv6_header (ipp,
1907 state->ri.remote_address.proto,
1908 sizeof (struct GNUNET_TUN_TcpHeader),
1909 &state->ri.remote_address.address.ipv6,
1910 &state->ri.local_address.address.ipv6);
1911 udp->spt = htons (state->ri.remote_address.port);
1912 udp->dpt = htons (state->ri.local_address.port);
1913 udp->len = htons (0);
1914 udp->crc = htons (0);
1915}
1916
1917
1918/**
1861 * Process a request to forward ICMP data to the Internet via this peer. 1919 * Process a request to forward ICMP data to the Internet via this peer.
1862 * 1920 *
1863 * @param cls closure, NULL 1921 * @param cls closure, NULL
@@ -1882,6 +1940,7 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1882 const struct in_addr *v4; 1940 const struct in_addr *v4;
1883 const struct in6_addr *v6; 1941 const struct in6_addr *v6;
1884 const void *payload; 1942 const void *payload;
1943 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8];
1885 int af; 1944 int af;
1886 1945
1887 GNUNET_STATISTICS_update (stats, 1946 GNUNET_STATISTICS_update (stats,
@@ -1899,7 +1958,14 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1899 pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage); 1958 pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage);
1900 1959
1901 af = (int) ntohl (msg->af); 1960 af = (int) ntohl (msg->af);
1902 state->ri.remote_address.af = af; 1961 if ( (NULL != state->heap_node) &&
1962 (af != state->ri.remote_address.af) )
1963 {
1964 /* other peer switched AF on this tunnel; not allowed */
1965 GNUNET_break_op (0);
1966 return GNUNET_SYSERR;
1967 }
1968
1903 switch (af) 1969 switch (af)
1904 { 1970 {
1905 case AF_INET: 1971 case AF_INET:
@@ -1917,6 +1983,48 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1917 payload = &v4[1]; 1983 payload = &v4[1];
1918 pkt_len -= sizeof (struct in_addr); 1984 pkt_len -= sizeof (struct in_addr);
1919 state->ri.remote_address.address.ipv4 = *v4; 1985 state->ri.remote_address.address.ipv4 = *v4;
1986 if (NULL == state->heap_node)
1987 {
1988 state->ri.remote_address.af = af;
1989 state->ri.remote_address.proto = IPPROTO_ICMP;
1990 setup_state_record (state);
1991 }
1992 /* check that ICMP type is something we want to support
1993 and possibly make up payload! */
1994 switch (msg->icmp_header.type)
1995 {
1996 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
1997 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
1998 break;
1999 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2000 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2001 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2002 if (0 != pkt_len)
2003 {
2004 GNUNET_break_op (0);
2005 return GNUNET_SYSERR;
2006 }
2007 /* make up payload */
2008 {
2009 struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) buf;
2010 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2011
2012 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2013 pkt_len = sizeof (struct GNUNET_TUN_IPv4Header) + 8;
2014 make_up_icmpv4_payload (state,
2015 ipp,
2016 udp);
2017 payload = ipp;
2018 }
2019 break;
2020 default:
2021 GNUNET_break_op (0);
2022 GNUNET_STATISTICS_update (stats,
2023 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2024 1, GNUNET_NO);
2025 return GNUNET_SYSERR;
2026 }
2027 /* end AF_INET */
1920 break; 2028 break;
1921 case AF_INET6: 2029 case AF_INET6:
1922 if (pkt_len < sizeof (struct in6_addr)) 2030 if (pkt_len < sizeof (struct in6_addr))
@@ -1933,8 +2041,52 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1933 payload = &v6[1]; 2041 payload = &v6[1];
1934 pkt_len -= sizeof (struct in6_addr); 2042 pkt_len -= sizeof (struct in6_addr);
1935 state->ri.remote_address.address.ipv6 = *v6; 2043 state->ri.remote_address.address.ipv6 = *v6;
1936 break; 2044 if (NULL == state->heap_node)
2045 {
2046 state->ri.remote_address.af = af;
2047 state->ri.remote_address.proto = IPPROTO_ICMP;
2048 setup_state_record (state);
2049 }
2050 /* check that ICMP type is something we want to support
2051 and possibly make up payload! */
2052 switch (msg->icmp_header.type)
2053 {
2054 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2055 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2056 break;
2057 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2058 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2059 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2060 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2061 if (0 != pkt_len)
2062 {
2063 GNUNET_break_op (0);
2064 return GNUNET_SYSERR;
2065 }
2066 /* make up payload */
2067 {
2068 struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) buf;
2069 struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
2070
2071 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2072 pkt_len = sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2073 make_up_icmpv6_payload (state,
2074 ipp,
2075 udp);
2076 payload = ipp;
2077 }
2078 break;
2079 default:
2080 GNUNET_break_op (0);
2081 GNUNET_STATISTICS_update (stats,
2082 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2083 1, GNUNET_NO);
2084 return GNUNET_SYSERR;
2085 }
2086 /* end AF_INET6 */
2087 break;
1937 default: 2088 default:
2089 /* bad AF */
1938 GNUNET_break_op (0); 2090 GNUNET_break_op (0);
1939 return GNUNET_SYSERR; 2091 return GNUNET_SYSERR;
1940 } 2092 }
@@ -1948,15 +2100,6 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1948 &state->ri.remote_address.address, 2100 &state->ri.remote_address.address,
1949 buf, sizeof (buf))); 2101 buf, sizeof (buf)));
1950 } 2102 }
1951
1952 /* FIXME: check that ICMP type is something we want to support */
1953
1954 state->ri.remote_address.proto = IPPROTO_ICMP;
1955 state->ri.remote_address.port = 0;
1956 state->ri.local_address.port = 0;
1957 if (NULL == state->heap_node)
1958 setup_state_record (state);
1959
1960 send_icmp_packet_via_tun (&state->ri.remote_address, 2103 send_icmp_packet_via_tun (&state->ri.remote_address,
1961 &state->ri.local_address, 2104 &state->ri.local_address,
1962 &msg->icmp_header, 2105 &msg->icmp_header,
@@ -1966,6 +2109,56 @@ receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1966 2109
1967 2110
1968/** 2111/**
2112 * Setup ICMP payload for ICMP error messages. Called
2113 * for both IPv4 and IPv6 addresses.
2114 *
2115 * @param state context for creating the IP Packet
2116 * @param buf where to create the payload, has at least
2117 * sizeof (struct GNUNET_TUN_IPv6Header) + 8 bytes
2118 * @return number of bytes of payload we created in buf
2119 */
2120static uint16_t
2121make_up_icmp_service_payload (struct TunnelState *state,
2122 char *buf)
2123{
2124 switch (state->serv->address.af)
2125 {
2126 case AF_INET:
2127 {
2128 struct GNUNET_TUN_IPv4Header *ipv4;
2129 struct GNUNET_TUN_UdpHeader *udp;
2130
2131 ipv4 = (struct GNUNET_TUN_IPv4Header *)buf;
2132 udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2133 make_up_icmpv4_payload (state,
2134 ipv4,
2135 udp);
2136 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2137 return sizeof (struct GNUNET_TUN_IPv4Header) + 8;
2138 }
2139 break;
2140 case AF_INET6:
2141 {
2142 struct GNUNET_TUN_IPv6Header *ipv6;
2143 struct GNUNET_TUN_UdpHeader *udp;
2144
2145 ipv6 = (struct GNUNET_TUN_IPv6Header *)buf;
2146 udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2147 make_up_icmpv6_payload (state,
2148 ipv6,
2149 udp);
2150 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
2151 return sizeof (struct GNUNET_TUN_IPv6Header) + 8;
2152 }
2153 break;
2154 default:
2155 GNUNET_break (0);
2156 }
2157 return 0;
2158}
2159
2160
2161/**
1969 * Process a request via mesh to send ICMP data to a service 2162 * Process a request via mesh to send ICMP data to a service
1970 * offered by this system. 2163 * offered by this system.
1971 * 2164 *
@@ -1988,6 +2181,9 @@ receive_icmp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel
1988 struct TunnelState *state = *tunnel_ctx; 2181 struct TunnelState *state = *tunnel_ctx;
1989 const struct GNUNET_EXIT_IcmpServiceMessage *msg; 2182 const struct GNUNET_EXIT_IcmpServiceMessage *msg;
1990 uint16_t pkt_len = ntohs (message->size); 2183 uint16_t pkt_len = ntohs (message->size);
2184 struct GNUNET_TUN_IcmpHeader icmp;
2185 char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8];
2186 const void *payload;
1991 2187
1992 GNUNET_STATISTICS_update (stats, 2188 GNUNET_STATISTICS_update (stats,
1993 gettext_noop ("# Bytes received from MESH"), 2189 gettext_noop ("# Bytes received from MESH"),
@@ -2013,23 +2209,141 @@ receive_icmp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel
2013 GNUNET_break_op (0); 2209 GNUNET_break_op (0);
2014 return GNUNET_SYSERR; 2210 return GNUNET_SYSERR;
2015 } 2211 }
2016 if (state->serv->address.af != ntohl (msg->af)) 2212 icmp = msg->icmp_header;
2213 payload = &msg[1];
2214 state->ri.remote_address = state->serv->address;
2215 setup_state_record (state);
2216
2217 /* check that ICMP type is something we want to support,
2218 perform ICMP PT if needed ans possibly make up payload */
2219 switch (msg->af)
2017 { 2220 {
2018 GNUNET_STATISTICS_update (stats, 2221 case AF_INET:
2019 gettext_noop ("# ICMP service requests discarded (incompatible af)"), 2222 switch (msg->icmp_header.type)
2020 1, GNUNET_NO); 2223 {
2224 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2225 if (state->serv->address.af == AF_INET6)
2226 icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
2227 break;
2228 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2229 if (state->serv->address.af == AF_INET6)
2230 icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
2231 break;
2232 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2233 if (state->serv->address.af == AF_INET6)
2234 icmp.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
2235 if (0 != pkt_len)
2236 {
2237 GNUNET_break_op (0);
2238 return GNUNET_SYSERR;
2239 }
2240 payload = buf;
2241 pkt_len = make_up_icmp_service_payload (state, buf);
2242 break;
2243 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2244 if (state->serv->address.af == AF_INET6)
2245 icmp.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
2246 if (0 != pkt_len)
2247 {
2248 GNUNET_break_op (0);
2249 return GNUNET_SYSERR;
2250 }
2251 payload = buf;
2252 pkt_len = make_up_icmp_service_payload (state, buf);
2253 break;
2254 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2255 if (state->serv->address.af == AF_INET6)
2256 {
2257 GNUNET_STATISTICS_update (stats,
2258 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2259 1, GNUNET_NO);
2260 return GNUNET_OK;
2261 }
2262 if (0 != pkt_len)
2263 {
2264 GNUNET_break_op (0);
2265 return GNUNET_SYSERR;
2266 }
2267 payload = buf;
2268 pkt_len = make_up_icmp_service_payload (state, buf);
2269 break;
2270 default:
2271 GNUNET_break_op (0);
2272 GNUNET_STATISTICS_update (stats,
2273 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2274 1, GNUNET_NO);
2275 return GNUNET_SYSERR;
2276 }
2277 /* end of AF_INET */
2278 break;
2279 case AF_INET6:
2280 switch (msg->icmp_header.type)
2281 {
2282 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2283 if (state->serv->address.af == AF_INET)
2284 icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
2285 break;
2286 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2287 if (state->serv->address.af == AF_INET)
2288 icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
2289 break;
2290 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2291 if (state->serv->address.af == AF_INET)
2292 icmp.type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
2293 if (0 != pkt_len)
2294 {
2295 GNUNET_break_op (0);
2296 return GNUNET_SYSERR;
2297 }
2298 payload = buf;
2299 pkt_len = make_up_icmp_service_payload (state, buf);
2300 break;
2301 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2302 if (state->serv->address.af == AF_INET)
2303 icmp.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
2304 if (0 != pkt_len)
2305 {
2306 GNUNET_break_op (0);
2307 return GNUNET_SYSERR;
2308 }
2309 payload = buf;
2310 pkt_len = make_up_icmp_service_payload (state, buf);
2311 break;
2312 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2313 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2314 if (state->serv->address.af == AF_INET)
2315 {
2316 GNUNET_STATISTICS_update (stats,
2317 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
2318 1, GNUNET_NO);
2319 return GNUNET_OK;
2320 }
2321 if (0 != pkt_len)
2322 {
2323 GNUNET_break_op (0);
2324 return GNUNET_SYSERR;
2325 }
2326 payload = buf;
2327 pkt_len = make_up_icmp_service_payload (state, buf);
2328 break;
2329 default:
2330 GNUNET_break_op (0);
2331 GNUNET_STATISTICS_update (stats,
2332 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2333 1, GNUNET_NO);
2334 return GNUNET_SYSERR;
2335 }
2336 /* end of AF_INET6 */
2337 break;
2338 default:
2339 GNUNET_break_op (0);
2021 return GNUNET_SYSERR; 2340 return GNUNET_SYSERR;
2022 } 2341 }
2023 2342
2024 /* FIXME: check that ICMP type is something we want to support */
2025
2026 state->ri.remote_address = state->serv->address;
2027 setup_state_record (state);
2028
2029 send_icmp_packet_via_tun (&state->ri.remote_address, 2343 send_icmp_packet_via_tun (&state->ri.remote_address,
2030 &state->ri.local_address, 2344 &state->ri.local_address,
2031 &msg->icmp_header, 2345 &icmp,
2032 &msg[1], pkt_len); 2346 payload, pkt_len);
2033 return GNUNET_YES; 2347 return GNUNET_YES;
2034} 2348}
2035 2349