# HG changeset patch # User linus.luessing@web.de # Date 1322615056 0 # Node ID 58d4a721f0c085851e9553f0760286e5966cbeef # Parent c37cd9c2da7f2998b22d2beb9d02c86de98f4dfd Fix IPv6 link local file transfer. Before bonjour did not accept a file transfer from IPv6 link local addresses due to the address in the xep bytestream message not containing an interface identifier and therefore not matching the saved bonjour buddy's IPv6 link local address which does contain an interface identifier. With this patch we will only check the address and skip the buddy's interface identifier in the case of an IPv6 link local address. committer: Ethan Blanton diff -r c37cd9c2da7f -r 58d4a721f0c0 libpurple/protocols/bonjour/bonjour_ft.c --- a/libpurple/protocols/bonjour/bonjour_ft.c Wed Nov 30 01:01:09 2011 +0000 +++ b/libpurple/protocols/bonjour/bonjour_ft.c Wed Nov 30 01:04:16 2011 +0000 @@ -492,6 +492,60 @@ purple_debug_info("bonjour", "si offer Message type - Unknown-%s.\n", type); } +/** + * Will compare a host with a buddy_ip. + * + * Additionally to a common '!strcmp(host, buddy_ip)', it will also return TRUE + * if 'host' is a link local IPv6 address without an appended interface + * identifier and 'buddy_ip' string is "host" + "%iface". + * + * Note: This may theoretically result in the attempt to connect to the wrong + * host, because we do not know for sure which interface the according link + * local IPv6 address might relate to and RFC4862 for instance only ensures the + * uniqueness of this address on a given link. So we could possibly have two + * distinct buddies with the same ipv6 link local address on two distinct + * interfaces. Unfortunately XEP-0065 does not seem to specify how to deal with + * link local ip addresses properly... + * However, in practice the possiblity for such a conflict is relatively low + * (2011 - might be different in the future though?). + * + * @param host ipv4 or ipv6 address string + * @param buddy_ip ipv4 or ipv6 address string + * @return TRUE if they match, FALSE otherwise + */ +static gboolean +xep_cmp_addr(const char *host, const char *buddy_ip) +{ +#if defined(AF_INET6) && defined(HAVE_GETADDRINFO) + struct addrinfo hint, *res = NULL; + int ret; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(host, NULL, &hint, &res); + if(ret) + goto out; + + if(res->ai_family != AF_INET6 || + !IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) { + freeaddrinfo(res); + goto out; + } + freeaddrinfo(res); + + if(strlen(buddy_ip) <= strlen(host) || + buddy_ip[strlen(host)] != '%') + return FALSE; + + return !strncmp(host, buddy_ip, strlen(host)); + +out: +#endif + return !strcmp(host, buddy_ip); +} + static gboolean __xep_bytestreams_parse(PurpleBuddy *pb, PurpleXfer *xfer, xmlnode *query, const char *iq_id) @@ -514,13 +568,13 @@ continue; } - if(strcmp(host, xf->buddy_ip)) + if(!xep_cmp_addr(host, xf->buddy_ip)) continue; g_free(xf->iq_id); xf->iq_id = g_strdup(iq_id); xf->jid = g_strdup(jid); - xf->proxy_host = g_strdup(host); + xf->proxy_host = g_strdup(xf->buddy_ip); xf->proxy_port = portnum; purple_debug_info("bonjour", "bytestream offer parse" "jid=%s host=%s port=%d.\n", jid, host, portnum);