Revision de1d579f1efd330d7acfb5a1a8e8e8957ca3ba54
evands at pidgin.im
evands at pidgin.im
Thu Mar 22 08:52:17 EDT 2007
o -----------------------------------------------------------------
| Revision: de1d579f1efd330d7acfb5a1a8e8e8957ca3ba54
| Ancestor: 508b969eb6b11cc64db8eb5e17f1699479731ef3
| Author: evands at pidgin.im
| Date: 2007-03-22T12:51:33
| Branch: im.pidgin.pidgin
|
| Modified files:
| libpurple/nat-pmp.c libpurple/nat-pmp.h libpurple/network.c
|
| ChangeLog:
|
| nat-pmp is now functional with a compatible router. I'm not enabling this code yet because it hasn't been tested with a router which doesn't support nat-pmp.
|
| ============================================================
| --- libpurple/nat-pmp.c c37ed4dd86f80cd55a504a59332aa75f13b75e55
| +++ libpurple/nat-pmp.c b7b50208c7e07447afb75b2f2890bd4dd3b0d91c
| @@ -52,14 +52,23 @@
| #include <net/if.h>
|
| #ifdef NET_RT_DUMP2
| +
| +#define PMP_DEBUG
| +
| /*
| * Thanks to R. Matthew Emerson for the fixes on this
| */
|
| +#define PMP_MAP_OPCODE_UDP 1
| +#define PMP_MAP_OPCODE_TCP 2
| +
| +#define PMP_VERSION 0
| +#define PMP_PORT 5351
| +#define PMP_TIMEOUT 250000 // 250000 useconds
| +
| /* alignment constraint for routing socket */
| -#define ROUNDUP(a) \
| -((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
| -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
| +#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
| +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
|
| static void
| get_rtaddrs(int bitmask, struct sockaddr *sa, struct sockaddr *addrs[])
| @@ -98,6 +107,9 @@ is_default_route(struct sockaddr *sa, st
| return 0;
| }
|
| +/*!
| + * The return sockaddr_in must be g_free()'d when no longer needed
| + */
| static struct sockaddr_in *
| default_gw()
| {
| @@ -106,31 +118,34 @@ default_gw()
| char *buf, *next, *lim;
| struct rt_msghdr2 *rtm;
| struct sockaddr *sa;
| - struct sockaddr *rti_info[RTAX_MAX];
| - struct sockaddr_in *sin;
| -
| + struct sockaddr_in *sin = NULL;
| + gboolean found = FALSE;
| +
| mib[0] = CTL_NET;
| - mib[1] = PF_ROUTE;
| - mib[2] = 0;
| - mib[3] = 0;
| + mib[1] = PF_ROUTE; /* entire routing table or a subset of it */
| + mib[2] = 0; /* protocol number - always 0 */
| + mib[3] = 0; /* address family - 0 for all addres families */
| mib[4] = NET_RT_DUMP2;
| mib[5] = 0;
|
| + /* Determine the buffer side needed to get the full routing table */
| if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
| {
| - err(1, "sysctl: net.route.0.0.dump estimate");
| + purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump estimate");
| + return NULL;
| }
|
| - buf = malloc(needed);
| -
| - if (buf == 0)
| + if (!(buf = malloc(needed)))
| {
| - err(2, "malloc");
| + purple_debug_warning("nat-pmp", "malloc");
| + return NULL;
| }
|
| + /* Read the routing table into buf */
| if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
| {
| - err(1, "sysctl: net.route.0.0.dump");
| + purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump");
| + return NULL;
| }
|
| lim = buf + needed;
| @@ -142,36 +157,51 @@ default_gw()
|
| if (sa->sa_family == AF_INET)
| {
| - sin = (struct sockaddr_in *)sa;
| - struct sockaddr addr, mask;
| -
| - get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
| - bzero(&addr, sizeof(addr));
| -
| - if (rtm->rtm_addrs & RTA_DST)
| - bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
| -
| - bzero(&mask, sizeof(mask));
| -
| - if (rtm->rtm_addrs & RTA_NETMASK)
| - bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
| -
| - if (is_default_route(&addr, &mask))
| + sin = (struct sockaddr_in*) sa;
| +
| + if ((rtm->rtm_flags & RTF_GATEWAY) && sin->sin_addr.s_addr == INADDR_ANY)
| {
| - sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY];
| - break;
| + /* We found the default route. Now get the destination address and netmask. */
| + struct sockaddr *rti_info[RTAX_MAX];
| + struct sockaddr addr, mask;
| +
| + get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
| + bzero(&addr, sizeof(addr));
| +
| + if (rtm->rtm_addrs & RTA_DST)
| + bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
| +
| + bzero(&mask, sizeof(mask));
| +
| + if (rtm->rtm_addrs & RTA_NETMASK)
| + bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
| +
| + if (rtm->rtm_addrs & RTA_GATEWAY &&
| + is_default_route(&addr, &mask))
| + {
| + if (rti_info[RTAX_GATEWAY]) {
| + struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY];
| + sin = g_new0(struct sockaddr_in, 1);
| + sin->sin_family = rti_sin->sin_family;
| + sin->sin_port = rti_sin->sin_port;
| + sin->sin_addr.s_addr = rti_sin->sin_addr.s_addr;
| + memcpy(sin, rti_info[RTAX_GATEWAY], sizeof(struct sockaddr_in));
| +
| + purple_debug_info("nat-pmp", "found a default gateway");
| + found = TRUE;
| + break;
| + }
| + }
| }
| }
| -
| - rtm = (struct rt_msghdr2 *)next;
| }
| -
| - free(buf);
| -
| - return sin;
| +
| + return (found ? sin : NULL);
| }
|
| -//! double_timeout(struct timeval *) will handle doubling a timeout for backoffs required by NAT-PMP
| +/*!
| + * double_timeout(struct timeval *) will handle doubling a timeout for backoffs required by NAT-PMP
| + */
| static void
| double_timeout(struct timeval *to)
| {
| @@ -278,9 +308,11 @@ iterate:
| ++req_attempts;
| double_timeout(&req_timeout);
| }
| -
| - if (publicsockaddr == NULL)
| +
| + if (publicsockaddr == NULL) {
| + g_free(gateway);
| return NULL;
| + }
|
| #ifdef PMP_DEBUG
| purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n");
| @@ -294,7 +326,9 @@ iterate:
| #endif
|
| publicsockaddr->sin_addr.s_addr = resp.address;
| -
| +
| + g_free(gateway);
| +
| return inet_ntoa(publicsockaddr->sin_addr);
| }
|
| @@ -302,7 +336,7 @@ pmp_map_response_t *
| * will return NULL on error, or a pointer to the pmp_map_response_t type
| */
| pmp_map_response_t *
| -purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
| +purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
| {
| struct sockaddr_in *gateway = default_gw();
|
| @@ -331,7 +365,7 @@ purple_pmp_create_map(uint8_t type, uint
| bzero(&req, sizeof(pmp_map_request_t));
| bzero(resp, sizeof(pmp_map_response_t));
| req.version = 0;
| - req.opcode = type;
| + req.opcode = ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP);
| req.privateport = htons(privateport); // What a difference byte ordering makes...d'oh!
| req.publicport = htons(publicport);
| req.lifetime = htonl(lifetime);
| @@ -393,6 +427,8 @@ iterate:
| purple_debug_info("nat-pmp", "lifetime: %d\n", ntohl(resp->lifetime));
| #endif
|
| + g_free(gateway);
| +
| return resp;
| }
|
| @@ -401,11 +437,13 @@ pmp_map_response_t *
| * will return NULL on error, or a pointer to the pmp_map_response_t type
| */
| pmp_map_response_t *
| -purple_pmp_destroy_map(uint8_t type, uint16_t privateport)
| +purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport)
| {
| - pmp_map_response_t *response = NULL;
| + pmp_map_response_t *response;
|
| - if ((response = purple_pmp_create_map(type, privateport, 0, 0)) == NULL)
| + response = purple_pmp_create_map(((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP),
| + privateport, 0, 0);
| + if (!response)
| {
| purple_debug_info("nat-pmp", "Failed to properly destroy mapping for %d!\n", privateport);
| return NULL;
| @@ -423,13 +461,13 @@ pmp_map_response_t *
| }
|
| pmp_map_response_t *
| -purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
| +purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
| {
| return NULL;
| }
|
| pmp_map_response_t *
| -purple_pmp_destroy_map(uint8_t type, uint16_t privateport)
| +purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport)
| {
| return NULL;
| }
| ============================================================
| --- libpurple/nat-pmp.h 501125d36575a7a8bcb7e1e18de52391ea57440c
| +++ libpurple/nat-pmp.h fde05a571347c5fd3ae9975f2ad0fbe908e10fa2
| @@ -41,20 +41,19 @@
| #include <net/if.h>
| #include <net/route.h>
|
| -#define PMP_VERSION 0
| -#define PMP_PORT 5351
| -#define PMP_TIMEOUT 250000 // 250000 useconds
| -#define PMP_LIFETIME 3600 // 3600 seconds
| +#define PURPLE_PMP_LIFETIME 3600 // 3600 seconds
|
| -#define PMP_MAP_UDP 1
| -#define PMP_MAP_TCP 2
| -
| /*
| * uint8_t: version, opcodes
| * uint16_t: resultcode
| * unint32_t: epoch (seconds since mappings reset)
| */
|
| +typedef enum {
| + PURPLE_PMP_TYPE_UDP,
| + PURPLE_PMP_TYPE_TCP
| +} PurplePmpType;
| +
| typedef struct {
| uint8_t version;
| uint8_t opcode;
| @@ -88,7 +87,7 @@ char *purple_pmp_get_public_ip();
| } pmp_map_response_t;
|
| char *purple_pmp_get_public_ip();
| -pmp_map_response_t *purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime);
| -pmp_map_response_t *purple_pmp_destroy_map(uint8_t type, uint16_t privateport);
| +pmp_map_response_t *purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime);
| +pmp_map_response_t *purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport);
|
| #endif
| ============================================================
| --- libpurple/network.c bbb743b65d53f76a80e8e511ff589eafab652e5b
| +++ libpurple/network.c f4abab72cf68a07f04246d6c244420ca5ab42363
| @@ -47,6 +47,8 @@
| #include "stun.h"
| #include "upnp.h"
|
| +/* #define ENABLE_NAT_PMP */
| +
| #ifdef ENABLE_NAT_PMP
| #include "nat-pmp.h"
| #endif
| @@ -79,9 +81,6 @@ struct _PurpleNetworkListenData {
| PurpleNetworkListenCallback cb;
| gpointer cb_data;
| UPnPMappingAddRemove *mapping_data;
| -#ifdef ENABLE_NAT_PMP
| - gboolean has_pmp_mapping;
| -#endif
| };
|
| #ifdef HAVE_LIBNM
| @@ -251,7 +250,21 @@ purple_network_set_upnp_port_mapping_cb(
| purple_network_listen_cancel(listen_data);
| }
|
| +static gboolean
| +purple_network_finish_pmp_map_cb(gpointer data)
| +{
| + PurpleNetworkListenData *listen_data;
| +
| + listen_data = data;
| +
| + if (listen_data->cb)
| + listen_data->cb(listen_data->listenfd, listen_data->cb_data);
|
| + purple_network_listen_cancel(listen_data);
| +
| + return FALSE;
| +}
| +
| static PurpleNetworkListenData *
| purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data)
| {
| @@ -348,15 +361,22 @@ purple_network_do_listen(unsigned short
|
| #ifdef ENABLE_NAT_PMP
| /* Attempt a NAT-PMP Mapping, which will return immediately */
| - listen_data->has_pmp_mapping = (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
| - actual_port, actual_port, PURPLE_PMP_LIFETIME) != NULL);
| + if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
| + actual_port, actual_port, PURPLE_PMP_LIFETIME) != NULL)
| + {
| + purple_debug_info("network", "Created NAT-PMP mapping on port %i",actual_port);
| + /* We want to return listen_data now, and on the next run loop trigger the cb and destroy listen_data */
| + purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
| + }
| + else
| #endif
| -
| - /* Attempt a UPnP Mapping */
| - listen_data->mapping_data = purple_upnp_set_port_mapping(
| - actual_port,
| - (socket_type == SOCK_STREAM) ? "TCP" : "UDP",
| - purple_network_set_upnp_port_mapping_cb, listen_data);
| + {
| + /* Attempt a UPnP Mapping */
| + listen_data->mapping_data = purple_upnp_set_port_mapping(
| + actual_port,
| + (socket_type == SOCK_STREAM) ? "TCP" : "UDP",
| + purple_network_set_upnp_port_mapping_cb, listen_data);
| + }
|
| return listen_data;
| }
| @@ -398,12 +418,6 @@ void purple_network_listen_cancel(Purple
| if (listen_data->mapping_data != NULL)
| purple_upnp_cancel_port_mapping(listen_data->mapping_data);
|
| -#ifdef ENABLE_NAT_PMP
| - if (listen_data->has_pmp_mapping)
| - purple_pmp_destroy_map(((listen_data->socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
| - purple_network_get_port_from_fd(listen_data->listenfd));
| -#endif
| -
| g_free(listen_data);
| }
|
To get the patch for this revision, please do this:
mtn log --last 1 --diffs --from de1d579f1efd330d7acfb5a1a8e8e8957ca3ba54
More information about the Commits
mailing list