📄 wps_upnp.c
字号:
/* * UPnP WPS Device * Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2006-2007 Sony Corporation * Copyright (c) 2008-2009 Atheros Communications * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * * See below for more details on licensing and code history. *//* * This has been greatly stripped down from the original file * (upnp_wps_device.c) by Ted Merrill, Atheros Communications * in order to eliminate use of the bulky libupnp library etc. * * History: * upnp_wps_device.c is/was a shim layer between wps_opt_upnp.c and * the libupnp library. * The layering (by Sony) was well done; only a very minor modification * to API of upnp_wps_device.c was required. * libupnp was found to be undesirable because: * -- It consumed too much code and data space * -- It uses multiple threads, making debugging more difficult * and possibly reducing reliability. * -- It uses static variables and only supports one instance. * The shim and libupnp are here replaced by special code written * specifically for the needs of hostapd. * Various shortcuts can and are taken to keep the code size small. * Generally, execution time is not as crucial. * * BUGS: * -- UPnP requires that we be able to resolve domain names. * While uncommon, if we have to do it then it will stall the entire * hostapd program, which is bad. * This is because we use the standard linux getaddrinfo() function * which is syncronous. * An asyncronous solution would be to use the free "ares" library. * -- Does not have a robust output buffering scheme. Uses a single * fixed size output buffer per TCP/HTTP connection, with possible (although * unlikely) possibility of overflow and likely excessive use of RAM. * A better solution would be to write the HTTP output as a buffered stream, * using chunking: (handle header specially, then) generate data with * a printf-like function into a buffer, catching buffer full condition, * then send it out surrounded by http chunking. * -- There is some code that could be separated out into the common * library to be shared with wpa_supplicant. * -- Needs renaming with module prefix to avoid polluting the debugger * namespace and causing possible collisions with other static fncs * and structure declarations when using the debugger. * -- Just what should be in the first event message sent after subscription * for the WLANEvent field? If i pass it empty, Vista replies with OK * but apparently barfs on the message. * -- The http error code generation is pretty bogus, hopefully noone cares. * * Author: Ted Merrill, Atheros Communications, based upon earlier work * as explained above and below. * * Copyright: * Copyright 2008 Atheros Communications. * * The original header (of upnp_wps_device.c) reads: * * Copyright (c) 2006-2007 Sony Corporation. All Rights Reserved. * * File Name: upnp_wps_device.c * Description: EAP-WPS UPnP device source * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sony Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions from Intel libupnp files, e.g. genlib/net/http/httpreadwrite.c * typical header: * * Copyright (c) 2000-2003 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*//* * Overview of WPS over UPnP: * * UPnP is a protocol that allows devices to discover each other and control * each other. In UPnP terminology, a device is either a "device" (a server * that provides information about itself and allows itself to be controlled) * or a "control point" (a client that controls "devices") or possibly both. * This file implements a UPnP "device". * * For us, we use mostly basic UPnP discovery, but the control part of interest * is WPS carried via UPnP messages. There is quite a bit of basic UPnP * discovery to do before we can get to WPS, however. * * UPnP discovery begins with "devices" send out multicast UDP packets to a * certain fixed multicast IP address and port, and "control points" sending * out other such UDP packets. * * The packets sent by devices are NOTIFY packets (not to be confused with TCP * NOTIFY packets that are used later) and those sent by control points are * M-SEARCH packets. These packets contain a simple HTTP style header. The * packets are sent redundantly to get around packet loss. Devices respond to * M-SEARCH packets with HTTP-like UDP packets containing HTTP/1.1 200 OK * messages, which give similar information as the UDP NOTIFY packets. * * The above UDP packets advertise the (arbitrary) TCP ports that the * respective parties will listen to. The control point can then do a HTTP * SUBSCRIBE (something like an HTTP PUT) after which the device can do a * separate HTTP NOTIFY (also like an HTTP PUT) to do event messaging. * * The control point will also do HTTP GET of the "device file" listed in the * original UDP information from the device (see UPNP_WPS_DEVICE_XML_FILE * data), and based on this will do additional GETs... HTTP POSTs are done to * cause an action. * * Beyond some basic information in HTTP headers, additional information is in * the HTTP bodies, in a format set by the SOAP and XML standards, a markup * language related to HTML used for web pages. This language is intended to * provide the ultimate in self-documentation by providing a universal * namespace based on pseudo-URLs called URIs. Note that although a URI looks * like a URL (a web address), they are never accessed as such but are used * only as identifiers. * * The POST of a GetDeviceInfo gets information similar to what might be * obtained from a probe request or response on Wi-Fi. WPS messages M1-M8 * are passed via a POST of a PutMessage; the M1-M8 WPS messages are converted * to a bin64 ascii representation for encapsulation. When proxying messages, * WLANEvent and PutWLANResponse are used. * * This of course glosses over a lot of details. */#include "includes.h"#include <assert.h>#include <net/if.h>#include <netdb.h>#include <sys/ioctl.h>#include "common.h"#include "uuid.h"#include "base64.h"#include "wps.h"#include "wps_i.h"#include "wps_upnp.h"#include "wps_upnp_i.h"/* * UPnP allows a client ("control point") to send a server like us ("device") * a domain name for registration, and we are supposed to resolve it. This is * bad because, using the standard Linux library, we will stall the entire * hostapd waiting for resolution. * * The "correct" solution would be to use an event driven library for domain * name resolution such as "ares". However, this would increase code size * further. Since it is unlikely that we'll actually see such domain names, we * can just refuse to accept them. */#define NO_DOMAIN_NAME_RESOLUTION 1 /* 1 to allow only dotted ip addresses *//* * UPnP does not scale well. If we were in a room with thousands of control * points then potentially we could be expected to handle subscriptions for * each of them, which would exhaust our memory. So we must set a limit. In * practice we are unlikely to see more than one or two. */#define MAX_SUBSCRIPTIONS 4 /* how many subscribing clients we handle */#define MAX_ADDR_PER_SUBSCRIPTION 8/* Write the current date/time per RFC */void format_date(struct wpabuf *buf){ const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat"; const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0" "Jul\0Aug\0Sep\0Oct\0Nov\0Dec"; struct tm *date; time_t t; t = time(NULL); date = gmtime(&t); wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT", &weekday_str[date->tm_wday * 4], date->tm_mday, &month_str[date->tm_mon * 4], date->tm_year + 1900, date->tm_hour, date->tm_min, date->tm_sec);}/*************************************************************************** * UUIDs (unique identifiers) * * These are supposed to be unique in all the world. * Sometimes permanent ones are used, sometimes temporary ones * based on random numbers... there are different rules for valid content * of different types. * Each uuid is 16 bytes long. **************************************************************************//* uuid_make -- construct a random UUID * The UPnP documents don't seem to offer any guidelines as to which method to * use for constructing UUIDs for subscriptions. Presumably any method from * rfc4122 is good enough; I've chosen random number method. */static void uuid_make(u8 uuid[UUID_LEN]){ os_get_random(uuid, UUID_LEN); /* Replace certain bits as specified in rfc4122 or X.667 */ uuid[6] &= 0x0f; uuid[6] |= (4 << 4); /* version 4 == random gen */ uuid[8] &= 0x3f; uuid[8] |= 0x80;}/* * Subscriber address handling. * Since a subscriber may have an arbitrary number of addresses, we have to * add a bunch of code to handle them. * * Addresses are passed in text, and MAY be domain names instead of the (usual * and expected) dotted IP addresses. Resolving domain names consumes a lot of * resources. Worse, we are currently using the standard Linux getaddrinfo() * which will block the entire program until complete or timeout! The proper * solution would be to use the "ares" library or similar with more state * machine steps etc. or just disable domain name resolution by setting * NO_DOMAIN_NAME_RESOLUTION to 1 at top of this file. *//* subscr_addr_delete -- delete single unlinked subscriber address * (be sure to unlink first if need be) */static void subscr_addr_delete(struct subscr_addr *a){ /* * Note: do NOT free domain_and_port or path because they point to * memory within the allocation of "a". */ os_free(a);}/* subscr_addr_unlink -- unlink subscriber address from linked list */static void subscr_addr_unlink(struct subscription *s, struct subscr_addr *a){ struct subscr_addr **listp = &s->addr_list; s->n_addr--; a->next->prev = a->prev; a->prev->next = a->next; if (*listp == a) { if (a == a->next) { /* last in queue */ *listp = NULL; assert(s->n_addr == 0); } else { *listp = a->next; } }}/* subscr_addr_free_all -- unlink and delete list of subscriber addresses. */static void subscr_addr_free_all(struct subscription *s){ struct subscr_addr **listp = &s->addr_list; struct subscr_addr *a; while ((a = *listp) != NULL) { subscr_addr_unlink(s, a); subscr_addr_delete(a); }}/* subscr_addr_link -- add subscriber address to list of addresses */static void subscr_addr_link(struct subscription *s, struct subscr_addr *a){ struct subscr_addr **listp = &s->addr_list; s->n_addr++; if (*listp == NULL) { *listp = a->next = a->prev = a; } else { a->next = *listp; a->prev = (*listp)->prev; a->prev->next = a; a->next->prev = a; }}/* subscr_addr_add_url -- add address(es) for one url to subscription */static void subscr_addr_add_url(struct subscription *s, const char *url){ int alloc_len; char *scratch_mem = NULL; char *mem; char *domain_and_port; char *delim; char *path; char *domain; int port = 80; /* port to send to (default is port 80) */ struct addrinfo hints; struct addrinfo *result = NULL; struct addrinfo *rp; int rerr; struct subscr_addr *a = NULL; /* url MUST begin with http: */ if (os_strncasecmp(url, "http://", 7)) goto fail; url += 7; /* allocate memory for the extra stuff we need */ alloc_len = (2 * (os_strlen(url) + 1)); scratch_mem = os_zalloc(alloc_len); if (scratch_mem == NULL) goto fail; mem = scratch_mem; strcpy(mem, url); domain_and_port = mem; mem += 1 + os_strlen(mem); delim = os_strchr(domain_and_port, '/'); if (delim) { *delim++ = 0; /* null terminate domain and port */ path = delim; } else { path = domain_and_port + os_strlen(domain_and_port); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -