我正在尝试实现SSDP协议,但我不确定它到底是如何工作的。SSDP通过udp发送数据,这一点很清楚。如果控制器连接到网络,它可以搜索带有MSEARCH消息的设备,该消息可以发送到组播地址239.255.255.250:1900。每个设备都必须侦听此地址并做出响应。但我不知道他们是怎么回应的。我在wireshark中看到他们使用单播响应,但我不知道如何确定接收响应的端口。
编辑
我正在尝试写ssdp fuzzer与spike模糊框架。正如我所说的,我能够发送正确的数据,但无法接收响应。我将尝试粘贴一些带有简短解释的spike代码。有Spike struct,它表示要发送的数据(它存储实际数据、大小、协议信息……)。我删除了一些变量以使其更清晰。
struct spike {
/*total size of all data*/
unsigned long datasize;
unsigned char *databuf;
unsigned char *endbuf;
int fd; /*for holding socket or file information*/
int proto; /*1 for tcp, 2 for udp*/
struct sockaddr_in *destsockaddr;
};现在我正在通过udp发送数据,并希望通过以下功能接收一些响应
spike_connect_udp(target,port);
spike_send();
s_read_packet(); 函数实现:
int
spike_connect_udp(char * host, int port)
{
int fd;
/*ahh, having udpstuff.c makes this stuff easy*/
fd=udpconnect(host,port);
if (fd==-1)
{
fprintf(stderr,"Couldn't udp connect to target\n");
return (0);
}
current_spike->fd=fd;
current_spike->proto=2; /*UDP*/
return 1;
}
int
udpconnect(const char * host, const unsigned short port )
{
int sfd = -1;
struct sockaddr_in addr;
/* Translate hostname from DNS or IP-address form */
memset(&addr, 0, sizeof(addr));
if (!getHostAddress(host, &addr))
{
hdebug("can't resolve host or address.\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = ntohs(port);
if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
hdebug("Could not create socket!\n");
return -1;
}
/* Now connect! */
if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
close(sfd);
return -1;
}
return sfd;
}
int
spike_send()
{
int retval;
switch (current_spike->proto)
{
case 1: /*TCP*/
//deleted, doesnt matter, i am sending via udp
case 2: /*UDP*/
//udp_write_data is function from framework
retval=udp_write_data(current_spike->fd, current_spike->destsockaddr, s_get_size(), s_get_databuf());
break;
}
fflush(0);
return retval;
}这可以很好地工作,并通过udp发送数据。现在我想通过打开套接字current_spike->fd接收一些响应。函数s_read_packet无效
s_read_packet()
{
unsigned char buffer[5000];
int i;
int size;
s_fd_wait();
printf("Reading packet\n");
memset(buffer,0x00,sizeof(buffer));
/what alarm and fcntl does?
alarm(1);
fcntl(current_spike->fd, F_SETFL, O_NONBLOCK);
//this read return error -1 and sets errno to 11 service temporarily unavailable
size=read(current_spike->fd,buffer,1500);
fcntl(current_spike->fd, F_SETFL, 0);
alarm(0);
for (i=0; i<size; i++)
{
if (isprint(buffer[i]))
printf("%c",buffer[i]);
else
printf("[%2.2x]",buffer[i]);
}
printf("\nDone with read\n");
}
int
s_fd_wait()
{
/*this function does a select to wait for
input on the fd, and if there
is, returns 1, else 0 */
int fd;
fd_set rfds;
struct timeval tv;
int retval;
fd=current_spike->fd;
/* Watch server_fd (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
/* Wait up to zero seconds . will this wait forever? not on linux.*/
/* from man page: timeout is an upper bound on the amount of time
elapsed before select returns. It may be zero, causing select
to return immediately. If timeout is NULL (no timeout), select
can block indefinitely. */
/*wait 2 seconds only*/
tv.tv_sec = TIMEINSECONDS;
tv.tv_usec = TIMEINUSECONDS;
//printf("Before select %d:%d\n",TIMEINSECONDS,TIMEINUSECONDS);
retval = select(fd+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
//printf("After select retval=%d.\n",retval);
switch (retval)
{
case 0:
/*Timeout - no packet or keypress*/
return(0);
break;
case -1:
/* ignore interrupted system calls */
if (errno != EINTR)
{
/*some kind of weird select error. Die. */
exit(-1);
}
/*otherwise we got interrupted, so just return false*/
return (0);
break;
default:
{
if (FD_ISSET(fd,&rfds))
return (1);
else
return (0);
}
}
} 但是函数s_read_packet不会产生数据...
发布于 2014-12-19 21:00:10
为了实现SSDP,您的应用程序需要能够将NOTIFY和M-SEARCH报头发送到指定的多播地址,并且还应该能够接收这些消息。为此,您需要创建一个专门的UDP套接字。
以下是如何初始化此类套接字的示例:
// Structs needed
struct in_addr localInterface;
struct sockaddr_in groupSock;
struct sockaddr_in localSock;
struct ip_mreq group;
// Create the Socket
int udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
// Enable SO_REUSEADDR to allow multiple instances of this application to receive copies of the multicast datagrams.
int reuse = 1;
setsockopt(udpSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
// Initialize the group sockaddr structure with a group address of 239.255.255.250 and port 1900.
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("239.255.255.250");
groupSock.sin_port = htons(1900);
// Disable loopback so you do not receive your own datagrams.
char loopch = 0;
setsockopt(udpSocket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch));
// Set local interface for outbound multicast datagrams. The IP address specified must be associated with a local, multicast capable interface.
localInterface.s_addr = inet_addr("192.168.0.1");
setsockopt(udpSocket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface));
// Bind to the proper port number with the IP address specified as INADDR_ANY.
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(1900);
localSock.sin_addr.s_addr = INADDR_ANY;
bind(udpSocket, (struct sockaddr*)&localSock, sizeof(localSock));
// Join the multicast group on the local interface. Note that this IP_ADD_MEMBERSHIP option must be called for each local interface over which the multicast datagrams are to be received.
group.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
group.imr_interface.s_addr = inet_addr("192.168.0.1");
setsockopt(udpSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group));现在,您可以使用此套接字将数据发送到组播组:
sendto(udpSocket, message, message_length, 0, (struct sockaddr*)&groupSock, sizeof(groupSock));要接收消息,请执行以下操作:
struct sockaddr_in si_other;
socklen_t slen = sizeof(si_other);
char buffer[1024];
recvfrom(udpSocket, buffer, 1024, 0, (struct sockaddr *) &si_other, &slen);要响应特定请求(如上接收),请执行以下操作:
sendto(udpSocket, message, message_length, 0, (struct sockaddr*)&si_other, sizeof(si_other));您现在要做的就是创建要发送的所需消息,并处理接收到的数据。假设您向多播组发送一个M-SEARCH请求(如上所述),那么您将从每个设备获得如下响应:
HTTP/1.1 200 OK
SERVER: Linux/2.6.15.2 UPnP/1.0 Mediaserver/1.0
CACHE-CONTROL: max-age=1200
LOCATION: http://192.168.0.223:5001/description.xml
ST: urn:schemas-upnp-org:device:MediaServer:4
USN: uuid:550e8400-e29b-11d4-a716-446655440000::urn:schemas-upnp-org:device:MediaServer:4
Content-Length: 0
EXT:发布于 2012-11-15 06:13:03
这个问题是关于TCP/UDP通信的一般原理,而不是关于SSDP的细节。如果作为UDP网络客户端的控制器打开到特定远程地址的套接字(无论是多播还是单播),则本地地址是适用的本地网络适配器地址,并且一些由操作系统分配的端口号。它看起来是随机的,但操作系统会仔细分配它,以管理使用同一网络适配器的所有应用程序的唯一性。在Wireshark中,您将看到类似以下内容:
IP, Src: 192.168.1.40 Dst: 239.255.255.250
UDP, Src Port: 42578 Dst Port: 1900其中192.168.1.40是控制器的(传出)网络地址。设备必须响应192.168.1.40:42578。UDP/IP堆栈实现提供了该元组。
我推荐阅读UPnP Device Architecture document。第一章是关于SSDP的,也正是你所问的部分:发现,广告和搜索。
添加代码后的编辑:
我没有看到任何“服务器”代码,任何bind()。您正在尝试对发送和接收使用相同的描述符。此外,您正在使用read(),这是一个用于连接资源的通用POSIX函数(当描述符为持久性时)。一般来说,在我看来,您只是以TCP客户端为例,更改了协议。它不能与UDP一起工作。要接收UDP数据包,必须在您的一侧设置一台服务器。UDP不知道某个数据包是否是对其他数据包的“响应”,就像TCP一样。UDP是无连接的,但您应该已经知道这一点。
我建议阅读通用UDP原理,尝试用UDP (random good looking start point)实现非常简单的回声服务器,然后在上面堆叠SSDP多播。
https://stackoverflow.com/questions/13382469
复制相似问题