C语言实现UPnP自动端口映射
来源:互联网 发布:java界面美化 编辑:程序博客网 时间:2024/06/05 08:38
UPnP端口自动映射程序:1、程序功能: 本质为UPnP Control Point程序,自动搜索IGD(Internet Gateway Device),发送相关命令包,使IGD进行相应Action,实现端口自动映射C语言实现的UPnP端口映射程序,linux平台程序如下:
#include "cmipv4.h"#ifdef _DEBUG#define DBG_INFO(x) printf x#else#define DBG_INFO(x)#endif#define TAGSTART "<%s>"#define TAGEND "</%s>"#define UPNP_SEARCH_ADDR "239.255.255.250"#define UPNP_SEARCH_PORT 1900#define UPNP_MSG_BUF_SIZE 8192#define UPPN_HTTP_VER "HTTP/1.1"#define XML_VERSION "1.0"#define RootDeviceUDN "upnp:rootdevice"#define UDNPREFIX "urn:schemas-upnp-org:device:"#define GATEWAYDEVICE0 "InternetGatewayDevice"#define GATEWAYDEVICE1 "WANDevice"#define GATEWAYDEVICE2 "WANConnectionDevice"#define UPNP_VER 1#if 0enum{ deviceType, presentationURL, friendlyName, manufacturer, manufacturerURL, modelDescription, modelName, modelNumber, UDN, UPC, serviceList, deviceList, ALL};enum{ POST, GET};char *Tag[ALL] = { "deviceType", "presentationURL", "friendlyName", "manufacturer", "manufacturerURL", "modelDescription", "modelName", "modelNumber", "UDN", "UPC", "serviceList", "deviceList"};typedef struct { int tag; char *tagName;}XML_Device;XML_Device deviceNodes[ALL] = { {deviceType, "deviceType"}, {presentationURL, "presentationURL"}, {friendlyName, "friendlyName"}, {manufacturer, "manufacturer"}, {manufacturerURL, "manufacturerURL"}, {modelDescription, "modelDescription"}, {modelName, "modelName"}, {modelNumber, "modelNumber"}, {UDN, "UDN"}, {UPC, "UPC"}, {serviceList, "serviceList"}, {deviceList, "deviceList"}};typedef struct _UPnPService{ char* ServiceType; char* ServiceId; char* ControlURL; char* SubscriptionURL; char* SCPDURL; char* SubscriptionID; int MaxVersion; struct UPnPAction *Actions; struct UPnPStateVariable *Variables; struct UPnPDevice *Parent; struct UPnPService *Next;}UPnPService;typedef struct _UPnPStateVariable{ struct UPnPStateVariable *Next; struct UPnPService *Parent; char* Name; char **AllowedValues; int NumAllowedValues; char* Min; char* Max; char* Step;}UPnPStateVariable;typedef struct _UPnPAction{ char* Name; struct UPnPAction *Next;}UPnPAction;typedef struct _UPnPAllowedValue{ struct UPnPAllowedValue *Next; char* Value;}UPnPAllowedValue;typedef struct _UPnPDevice{ char *deviceType; char *presentationURL; char *friendlyName; char *manufacturer; char *manufacturerURL; char *modelDescription; char *modelName; char *modelNumber; char *UDN; char *UPC; struct _UPnPDevice *Parent; struct _UPnPDevice *EmbededDevices; struct _UPnPDevice *Next; UPnPService *Services;}UPnPDevice;typedef struct _XMLNode{ char *name; int nameLen; struct _XMLNode *parent; struct _XMLNode *next; struct _XMLNode *peer; }XMLNode;typedef struct{ char *name; int nameLen; char *value; int valueLen; XMLNode *parent; }XML_PROPERTY;typedef struct{ char searchTarget[64]; char host[16]; }UPnPSearchPara;#endiftypedef struct{ char ExternalIP[16]; unsigned short ExternalPort; int Protocol;//0:TCP 1:UDP char InternalIP[16]; unsigned short InternalPort; int Enabled;// char Description[64]; long Duration;}UPNP_PORTMAPINFO; char *SearchFormat = "M-SEARCH * HTTP/1.1\r\n\MX: 5\r\n\ST: %s\r\n\HOST: 239.255.255.250:1900\r\n\MAN: \"ssdp:discover\"\r\n\Content-Length: 0\r\n\\r\n";char *GetFormat = "GET /%s HTTP/1.1\r\n\Accept: text/xml, application/xml\r\n\User-Agent: HC-NVS\r\n\Host: %s:%d\r\n\Connection: Keep-Alive\r\n\Cache-Control: max-age=0\r\n\\r\n"; char *HttpFormat ="POST %s HTTP/1.1\r\n\Host: %s:%d\r\n\SOAPACTION: \"%s#%s\"\r\n\CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n\Content-Length: %d\r\n\r\n"; char *SoapFormat ="<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n\<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n\<s:Body>\r\n<u:%s xmlns:u=\"%s\">\r\n%s</u:%s>\r\n</s:Body>\r\n</s:Envelope>\r\n";static char controlUrl[1024] ="";static char controlService[1024] = "";static char deviceAddr[1024] = "";static char deviceIP[16] = "";static char externalIP[16] = "";static int devicePort;static char postUrl[512] = "";static char location[128] = "";int UPnP_GetPropertyByName(char *xml, char *name, char *value){ char *startTag = NULL; char *endTag = NULL; //int start; //int end; char *p1 = NULL; char *p2 = NULL; //int valueLen; startTag = (char*)malloc(strlen(name)+3); if(!startTag) return ERROR; endTag = (char*)malloc(strlen(name)+4); if(!endTag) return ERROR; sprintf(startTag, "<%s>", name); sprintf(endTag, "</%s>", name); if(!(p1 = strstr(xml, startTag))) { free(startTag); free(endTag); return ERROR; } if(!(p2 = strstr(p1, endTag))) { free(startTag); free(endTag); return ERROR; } //size enough memcpy(value, p1+strlen(startTag), p2-p1-strlen(startTag)); value[p2-p1-strlen(startTag)] = '\0'; //printf("%s\n",value); free(startTag); free(endTag); return strlen(value);}int UPnP_InvokeCmd(char *cmd, char *response, int responsesize){ int upnp_sock; int ret; int len; int contentLen; int headLen; char *p = NULL; struct in_addr addr; if(!cmd||!response) return ERROR; len = strlen(cmd); ret = inet_pton(AF_INET, deviceIP, &addr); if(ret <= 0) { printf("IGD IP not valid.\n"); return ERROR; } if(devicePort<=0||devicePort>65535) { printf("IGD Port not valid.\n"); return ERROR; } upnp_sock = cmLink(inet_addr(deviceIP), devicePort, 0, 3000); if(upnp_sock == ERROR) { DBG_INFO(("upnp link device create socket failed.\n")); return ERROR; } //printf("after link host.\n"); /*Send packet*/ ret = cmSend(upnp_sock, cmd, len); if(ret != OK) { DBG_INFO(("UPnP send failed.\n")); goto __failed; } ret = cmWait(upnp_sock, 20000); if(ret <= 0) { DBG_INFO(("sock timeout .\n")); goto __failed; } len = cmRecv(upnp_sock, response, responsesize); if(len <= 0) { DBG_INFO(("receive error.\n")); goto __failed; } p = strstr(response, "\r\n\r\n"); if(!p) { return ERROR; } headLen = p-response+strlen("\r\n\r\n"); p = strstr(response, "Content-Length:"); if(p) { sscanf(p, "%*[^0-9]%d", &contentLen); if(len<contentLen+headLen) { ret = cmRead(upnp_sock, response+strlen(response), contentLen-(strlen(response)-headLen)); if(ret != OK) { DBG_INFO(("UPnP Read XML content failed.\n")); goto __failed; } } } DBG_INFO(("<<<<<<<<<<<:\n%s\n", response)); if(upnp_sock>=0) { cmClose(upnp_sock); upnp_sock = -1; } if((p = strstr(response, "200 OK")) == NULL) { return ERROR; } return OK; __failed: if(upnp_sock>=0) { cmClose(upnp_sock); upnp_sock = -1; } return ERROR;}int UPnP_GetDeviceDescription(){ int ret; char *p = NULL; char *p1 = NULL; char value[1024]; char request[1024]; char tempbuf[10240]; char URLBase[1024]; /*build GET packet*/ sprintf(request, GetFormat, postUrl, deviceIP,devicePort); ret = strlen(request); request[ret] = '\0'; DBG_INFO((">>>>>>>> \n%s\n", request)); memset(tempbuf, 0, 10240); ret = UPnP_InvokeCmd(request, tempbuf, 10240); if(ret != OK) { DBG_INFO(("UPnP invoke Get description failed.\n")); return ERROR; } /*Response state is 200 OK ?*/ if((p = strstr(tempbuf, "200 OK")) == NULL) return ERROR; /*Parse Xml, get service contral URL*/ ret = UPnP_GetPropertyByName(tempbuf, "URLBase", URLBase); //printf("ret = %d\n", ret); if(ret <= 0) { sprintf(URLBase, "http://%s:%d", deviceIP, devicePort); } //if(URLBase[strlen(URLBase)-1] != '/') //{ // strcat(URLBase, "/"); //} DBG_INFO(("URLBase is :%s.\n",URLBase)); p = strstr(tempbuf, "<deviceType>"); UPnP_GetPropertyByName(p, "deviceType", value); if(!strcmp(value, "urn:schemas-upnp-org:device:InternetGatewayDevice:1")) { p1 = strstr(p+strlen(value)+25, "<deviceType>"); UPnP_GetPropertyByName(p1, "deviceType", value); //printf("%s.\n", value); if(!strcmp(value, "urn:schemas-upnp-org:device:WANDevice:1")) { p = strstr(p1+strlen(value)+25, "<deviceType>"); UPnP_GetPropertyByName(p, "deviceType", value); if(!strcmp(value, "urn:schemas-upnp-org:device:WANConnectionDevice:1")) { p1 = strstr(p+strlen(value)+25, "<serviceType>"); UPnP_GetPropertyByName(p1, "serviceType", value); if(!strcmp(value, "urn:schemas-upnp-org:service:WANIPConnection:1") ||!strcmp(value, "urn:schemas-upnp-org:service:WANPPPConnection:1")) { strcpy(controlService, value); p = strstr(p1+strlen(value), "<controlURL>"); ret = UPnP_GetPropertyByName(p, "controlURL", value); if(ret == 0) return ERROR; strcpy(postUrl, value); strcat(URLBase, value); strcpy(controlUrl, URLBase); DBG_INFO(("controlUrl is %s.\n", controlUrl)); //sscanf(URLBase, "%*[^0-9]%[^:]:%d/%s", ip, &port, postUrl); //printf("%s.\n", postUrl); return OK; } } } } return ERROR; }int UPnP_GetExternalIPAddress(){ char out[10240]; char temp[10240]; char *p = NULL; char *p1 = NULL; int len; int ret; sprintf(temp, SoapFormat, "GetExternalIPAddress", controlService, "", "GetExternalIPAddress"); len = strlen(temp); sprintf(out, HttpFormat, postUrl, deviceIP, devicePort, controlService, "GetExternalIPAddress", len); strcat(out, temp); len = strlen(out); DBG_INFO((">>>>>>>>>>>>\n%s.\n", out)); memset(temp, 0, 10240); ret = UPnP_InvokeCmd(out, temp, 10240); if(ret != OK) { DBG_INFO(("UPnP invoke GetExternalIP failed.\n")); return ERROR; } if((p = strstr(temp, "200 OK")) == NULL) { return ERROR; } if((p = strstr(temp, "<NewExternalIPAddress"))!=NULL) { p1 = strstr(p, ">"); sscanf(p1, "%*[^0-9]%[^<]", externalIP); } return OK; }#if 1int UPnP_GetPortMappingInfo( int PortMappingIndex, UPNP_PORTMAPINFO *info){ char out[10240]; char temp[10240]; char *p = NULL; char *p1 = NULL; int len; int ret; char Action_GetPort_Format[64] = {"<NewPortMappingIndex>%d</NewPortMappingIndex>"}; sprintf(out, Action_GetPort_Format, PortMappingIndex); len = strlen(out); sprintf(temp, SoapFormat, "GetGenericPortMappingEntry", controlService, out, "GetGenericPortMappingEntry"); len = strlen(temp); sprintf(out, HttpFormat, postUrl, deviceIP, devicePort, controlService, "GetGenericPortMappingEntry", len); strcat(out, temp); len = strlen(out); DBG_INFO((">>>>>>>>>>>>\n%s.\n", out)); memset(temp, 0, 10240); ret = UPnP_InvokeCmd(out, temp, 10240); if(ret != OK) { DBG_INFO(("UPnP invoke GetPortMappingInfo failed.\n")); return ERROR; } if((p = strstr(temp, "200 OK")) == NULL) { return ERROR; } else { if((p = strstr(temp, "<NewExternalPort")) != NULL) { p1 = strstr(p, ">"); sscanf(p1, "%*[^0-9]%d", &info->ExternalPort); } if((p = strstr(temp, "<NewProtocol"))!=NULL) { p1 = strstr(p, ">"); if(!strncmp("TCP", p1+1, 3)) info->Protocol = 0; else if(!strncmp("UDP", p1+1, 3)) info->Protocol = 1; } if((p = strstr(temp, "<NewInternalPort"))!=NULL) { p1 = strstr(p, ">"); sscanf(p1, "%*[^0-9]%d", &info->InternalPort); } if((p = strstr(temp, "<NewInternalClient"))!=NULL) { p1 = strstr(p, ">"); sscanf(p1+1, "%[^<]", info->InternalIP); } if((p = strstr(temp, "<NewEnabled"))!=NULL) { p1 = strstr(p, ">"); sscanf(p1, "%*[^0-9]%d", &info->Enabled); } if((p = strstr(temp, "<NewPortMappingDescription"))!=NULL) { p1 = strstr(p ,">"); sscanf(p1+1, "%[^<][64]", info->Description); } if((p = strstr(temp, "<NewLeaseDuration>"))!=NULL) { p1 = strstr(p, ">"); sscanf(p1, "%*[^0-9]%d", &info->Duration); } } return OK;}int UPnP_PrintPortMap(){ int i = 0; int ret; UPNP_PORTMAPINFO info; printf("\n\n---------------------------------------------------------------\n"); printf("This Internet Gateway Device's UPnP PortMapping Information is :\n"); printf("---------------------------------------------------------------\n"); printf("\n%s %s %s %s %s %s \n", "Protocol", "ExternalPort", "InternalIP", "InternalPort", "Description", "Ena"); while(1) { ret = UPnP_GetPortMappingInfo(i++, &info); if(ret != OK) { printf("---------------------------------------------------------------\n\n"); break; } else { printf("%5s%13d%20s%12d%24.22s%5d\n", (info.Protocol == 0)?"TCP":"UDP", info.ExternalPort, info.InternalIP, info.InternalPort, info.Description, info.Enabled); } } return OK;}#endifint UPnP_AddPortMapping(const char *RemoteHose, unsigned short ExternalPort, const char *PortMappingProtocal, unsigned short InternalPort, const char *InternalClient, const char *PortMappingDescription, int PortMappingEnable, unsigned long PortMappingLeaseDuration){ char out[10240]; char temp[10240]; char *p = NULL; int len; int ret; char Action_AddPort_Format[512] = {"<NewRemoteHost></NewRemoteHost>\r\n\<NewExternalPort>%d</NewExternalPort>\r\n\<NewProtocol>%s</NewProtocol>\r\n\<NewInternalPort>%d</NewInternalPort>\r\n\<NewInternalClient>%s</NewInternalClient>\r\n\<NewEnabled>1</NewEnabled>\r\n\<NewPortMappingDescription>%s</NewPortMappingDescription>\r\n\<NewLeaseDuration>%d</NewLeaseDuration>\r\n"}; sprintf(out, Action_AddPort_Format, ExternalPort, PortMappingProtocal, InternalPort, InternalClient, PortMappingDescription, PortMappingLeaseDuration); len = strlen(out); sprintf(temp, SoapFormat, "AddPortMapping", controlService, out, "AddPortMapping"); len = strlen(temp); sprintf(out, HttpFormat, postUrl, deviceIP, devicePort, controlService, "AddPortMapping", len); strcat(out, temp); len = strlen(out); DBG_INFO((">>>>>>>>>>>>\n%s.\n", out)); memset(temp, 0, 10240); ret = UPnP_InvokeCmd(out, temp, 10240); if(ret != OK) { DBG_INFO(("UPnP invoke AddPortMapping failed.\n")); return ERROR; } if((p = strstr(temp, "200 OK")) == NULL) return ERROR; return OK;}int UPnP_FindDevice(){ int len, ret; char *p = NULL; char *p1 = NULL; int upnp_localsock, upnp_localport; struct sockaddr_in qAddr, addr; char Location[128]; char buf[UPNP_MSG_BUF_SIZE] = {0}; bzero((char*)&qAddr, sizeof(qAddr)); qAddr.sin_family = AF_INET; qAddr.sin_port = htons(UPNP_SEARCH_PORT); qAddr.sin_addr.s_addr = inet_addr(UPNP_SEARCH_ADDR); /*create udp sock*/ upnp_localsock = cmUdpStart(33445); if(upnp_localsock < 0) { DBG_INFO(("UPnP sock create failed.\n")); goto __failed; } /*join multicast*/ ret = cmJoin(upnp_localsock, inet_addr(UPNP_SEARCH_ADDR)); if(ret < 0) { DBG_INFO(("UPnP join failed.\n")); goto __failed; } /*build and send search(IGD) msg */ sprintf(buf, SearchFormat, "upnp:rootdevice"/*"urn:schemas-upnp-org:device:InternetGatewayDevice:1"*/); len = strlen(buf); DBG_INFO((">>>>>>>>>>:\n%s\n",buf)); ret = cmSendto(upnp_localsock, buf, len, &qAddr); ret = cmSendto(upnp_localsock, buf, len, &qAddr); if(ret == ERROR) { DBG_INFO(("UPnP send search packet failed.\n")); goto __failed; } /*receive response for search*/ ret = cmWait(upnp_localsock, 7000); if(ret <= 0) { DBG_INFO(("sock 7s timeout .\n")); goto __failed; } memset(buf, 0, UPNP_MSG_BUF_SIZE); ret = cmRecvfrom(upnp_localsock, buf, UPNP_MSG_BUF_SIZE, &addr); if(ret <= 0) { DBG_INFO(("UPnP receive response for search faield.\n")); goto __failed; } buf[ret] = '\0'; DBG_INFO(("<<<<<<<<<\n%s\n",buf)); /*search session over, close the socket*/ if(upnp_localsock>=0) { cmClose(upnp_localsock); upnp_localsock = -1; } /*sample is http OK*/ if(strstr(buf, "200 OK") == NULL) { DBG_INFO(("UPnP receive bad http response. failed.\n")); return ERROR; } /*find Location value*/ p = strstr(buf, "Location"); if(!p) return ERROR; p1 = strstr(p, "\r\n"); if(!p1) return ERROR; memcpy(Location, p, p1-p); Location[p1-p] = '\0'; DBG_INFO(("UPnP get Location: %s.\n", Location)); //get description accroding host:port\path strcpy(deviceAddr, Location); p = strstr(Location, "http://"); if(!p) { DBG_INFO(("Location not viladate")); return ERROR; } //parse ip port post sscanf(p, "%*[^0-9]%[^:]:%d/%s", deviceIP, &devicePort, postUrl); DBG_INFO(("Device location %s:%d/%s\n", deviceIP, devicePort, postUrl)); return OK; __failed: if(upnp_localsock>=0) { cmClose(upnp_localsock); upnp_localsock = -1; } return ERROR; }int main(int argc, char *argv[]){ char inteIP[16]; char extIP[16]; int intePort; int extPort; char protocol[4]; char description[16]; int enabled; int ret; int i; struct in_addr addr; char cmd; for(i=0;i<3;i++) { ret = UPnP_FindDevice(); if(ret == OK) { UPnP_GetDeviceDescription(); break; } } if(ret != OK) { printf("\nThere is no Internet Gateway Device finded.You can try again later.Quit.\n"); return ERROR; } UPnP_GetExternalIPAddress(); if((strlen(externalIP) != 0)&&(strlen(deviceIP) != 0)) { printf("Find A Internet Gateway Device. External IP is %s. Internal IP is %s.\n", externalIP, deviceIP); } else { printf("There is no Internet Gateway Device finded.You can try again later.Quit.\n"); return ERROR; } if(argc > 1) { if(strlen(argv[1]) != 2) { printf("cmd error.\n"); return ERROR; } ret = sscanf(argv[1], "-%c", &cmd); if(ret !=1) { printf("cmd error.\n"); return ERROR; } switch(cmd) { case 'a': if(argc != 6+2) { printf("AddPortMapping Action CMD Error.\n"); break; } else { if(strcmp(argv[2], "TCP")&&strcmp(argv[2], "UDP")) { printf("AddPortMapping Action CMD Error.---Protocol must is TCP or UDP.\n"); break; } else strcpy(protocol, argv[2]); if((ret = sscanf(argv[3], "%d", &extPort)) != 1) { printf("AddPortMapping Action CMD Error.---ExternalPort must is a int 0-65535.\n"); break; } ret = inet_pton(AF_INET, argv[4], &addr); if(ret <= 0) { printf("AddPortMapping Action CMD Error.---InternalIP not valid.\n"); break; } else strcpy(inteIP, argv[4]); if((ret = sscanf(argv[5], "%d", &intePort)) != 1) { printf("AddPortMapping Action CMD Error.---InternalPort must is a int 0-65535.\n"); break; } if(strlen(argv[6]) >=15) { printf("AddPortMapping Action CMD Error.---description too long. ONLY GET 15 chars"); strncpy(description, argv[6], 15); } else strcpy(description, argv[6]); if((strcmp(argv[7], "1"))&&(strcmp(argv[7], "0"))) { printf("AddPortMapping Action CMD Error.---Enabled must 1 or 0.\n"); break; } else sscanf(argv[7], "%d", &enabled); UPnP_AddPortMapping("", extPort, protocol, intePort, inteIP, description, enabled, 0); printf("AddPortMapping Action Successed.\n"); } break; case 'i': UPnP_PrintPortMap(); break; case 'h': printf("\nUPnP Port Mapping Tool.\n"); printf("\t-a Add Port Mapping.\n\t\teg.upnp -a TCP{protocol} 8000{ExternalPort} 192.168.10.11{InternalIP} 8000{InternalPort} NVS-Manage{Description} 1{Enabled}\n"); printf("\t-i Print Port Mapping Infomation.\n\t\teg.upnp -i\n"); break; default: printf("NO such cmd. use upnp -h get help info.\n"); break; } } return 0;}
- C语言实现UPnP自动端口映射
- UPNP自动端口映射的实现与路由器UPNP相关资料
- UPNP自动端口映射的实现与路由器UPNP相关资料
- UPNP端口映射Android实现
- UPnP端口映射实现过程(一)
- UPnP端口映射实现过程(二)
- UPnP端口映射的实现[转载]
- Upnp端口映射 C++类 实现
- UPnP 端口映射
- upnp 端口映射
- upnp端口映射
- upnp 端口映射
- [无线电易读版]基于STM32和W5500的UPnP自动端口映射功能实现
- UPNP--动态端口映射
- 端口映射与UPnP
- UPNP端口映射全过称
- UPNP端口映射全过称
- [C语言(VC)] ZXPortMap 端口映射源代码
- 2012.12.2(抽象类和抽象方法的区别)
- MFC获取控件位置
- How to Get Startup Ideas
- 僵尸进程
- Mapbar的基本算法
- C语言实现UPnP自动端口映射
- 黑马程序员_c#面向对象基础:聊天机器人
- Java环境变量的配置
- fast FW150US USB无线网卡Linux驱动安装
- 快学Scala习题解答—第一章 基础
- 利用录音AudioRecord实现吹一吹效果
- 排序算法总结
- Asp.net Web Api源码调试
- LightOJ 1058 & Poj 1971 Parallelogram Counting