Adding minissdpd

This commit is contained in:
Thomas Bernard 2011-09-28 21:14:08 +02:00
parent 0d96346588
commit d535e18678
21 changed files with 2276 additions and 0 deletions

59
minissdpd/Changelog.txt Normal file
View File

@ -0,0 +1,59 @@
$Id: Changelog.txt,v 1.19 2011/07/30 13:16:22 nanard Exp $
VERSION 1.1:
2011/07/30:
fixes. More overflow checks
2011/07/29:
added a lot of buffer overflow checks. Check malloc() failure, etc.
Better cleanup in case of crash at start.
network interface watch to add/drop multicast membership when the interface get live.
2011/06/18:
Starting to add support for UPnP Device Architecture v1.1
2011/05/23:
Added IPv6 support.
-i option now understands interface names as well as addresses.
VERSION 1.0:
2008/10/07:
added codelength.h
Fixing response to M-SEARCH
Doc update
2008/10/06:
UPnP server support (answering M-SEARCH)
2008/10/04:
listening on several interfaces.
2008/10/01:
use of daemon() instead of home made daemonize.
2007/12/19:
added uuid in responses
3 types of requests supported.
preventing buffer overflow
2007/12/18:
It is now possible to change the location of both pid file and
unix socket.
2007/10/08:
Added a man page
2007/09/27:
Support for install in different location $ PREFIX=... make install
2007/09/23:
added a script for use in /etc/init.d
improved Makefile
creating /var/run/minissdpd.pid
adding synthetic messages for new devices/removed devices
2007/09/19:
Take SSDP announce packets lifetime into account.

26
minissdpd/LICENSE Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2007-2009, Thomas BERNARD
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.
* The name of the author may not 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.

62
minissdpd/Makefile Normal file
View File

@ -0,0 +1,62 @@
# $Id: Makefile,v 1.13 2011/07/29 15:21:12 nanard Exp $
# MiniUPnP project
# author: Thomas Bernard
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# for use with GNU Make (gmake)
# install with :
# $ PREFIX=/tmp/dummylocation make install
# or
# $ INSTALLPREFIX=/usr/local make install
# or
# make install (miniupnpd will be put in /usr/sbin)
#
# install target is made for linux... sorry BSD users...
#CFLAGS = -Wall -g -D_GNU_SOURCE -Wstrict-prototypes
CFLAGS = -Wall -Os -D_GNU_SOURCE -fno-strict-aliasing -Wstrict-prototypes
CC = gcc
RM = rm -f
INSTALL = install
#EXECUTABLES = minissdpd testminissdpd listifaces
EXECUTABLES = minissdpd testminissdpd testcodelength
MINISSDPDOBJS = minissdpd.o openssdpsocket.o daemonize.o upnputils.o ifacewatch.o
TESTMINISSDPDOBJS = testminissdpd.o
ALLOBJS = $(MINISSDPDOBJS) $(TESTMINISSDPDOBJS) testcodelength.o
INSTALLPREFIX ?= $(PREFIX)/usr
SBININSTALLDIR = $(INSTALLPREFIX)/sbin
.PHONY: all clean install depend
all: $(EXECUTABLES)
clean:
$(RM) $(ALLOBJS) $(EXECUTABLES)
install: minissdpd
$(INSTALL) -d $(SBININSTALLDIR)
$(INSTALL) minissdpd $(SBININSTALLDIR)
$(INSTALL) -d $(PREFIX)/etc/init.d
$(INSTALL) minissdpd.init.d.script $(PREFIX)/etc/init.d/minissdpd
minissdpd: $(MINISSDPDOBJS)
$(CC) $(CFLAGS) -o $@ $(MINISSDPDOBJS)
testminissdpd: $(TESTMINISSDPDOBJS)
testcodelength: testcodelength.o
depend:
makedepend -f$(MAKEFILE_LIST) -Y \
$(ALLOBJS:.o=.c) 2>/dev/null
# DO NOT DELETE
minissdpd.o: config.h upnputils.h openssdpsocket.h daemonize.h codelength.h
minissdpd.o: ifacewatch.h
openssdpsocket.o: config.h openssdpsocket.h
daemonize.o: daemonize.h config.h
upnputils.o: config.h upnputils.h
ifacewatch.o: config.h openssdpsocket.h
testcodelength.o: codelength.h

36
minissdpd/README Normal file
View File

@ -0,0 +1,36 @@
protocole :
connection à la socket unix.
envoie d'une requete, retour d'une reponse.
fermeture de la connexion.
format de requete :
1 octet : type de la requete
1 - type
2 - USN (id unique)
3 - tout
n octets longueur de la chaine : 1 octet si < 128 sinon le bit haut
indique s'il existe un octet suplementaire, etc...
n octets = chaine
format reponse :
1 octet : nombre de reponses
pour chaque rep :
URL :
n octets longueur de la chaine
n octets = chaine Location
ST:
n octets longueur de la chaine
n octets = chaine type
USN:
n octets longueur de la chaine
n octets = chaine identifiant
Type de requete 4 = submit service
1 octet = 4
(k,n) octets : longueur et chaine "ST" (service type)
(k,n) octets : longueur et chaine "USN"
(k,n) octets : longueur et chaine "Server"
(k,n) octets : longueur et chaine "Location"
Pas de reponse

1
minissdpd/VERSION Normal file
View File

@ -0,0 +1 @@
1.1

31
minissdpd/codelength.h Normal file
View File

@ -0,0 +1,31 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef __CODELENGTH_H__
#define __CODELENGTH_H__
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
if((p) >= (p_limit)) break; \
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif

22
minissdpd/config.h Normal file
View File

@ -0,0 +1,22 @@
/* $Id: config.h,v 1.4 2011/05/23 12:22:29 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef __CONFIG_H__
#define __CONFIG_H__
/* use BSD daemon() ? */
#define USE_DAEMON
/* set the syslog facility to use. See man syslog(3) and syslog.conf(5). */
#define LOG_MINISSDPD LOG_DAEMON
/* enable IPv6 */
#define ENABLE_IPV6
/* Maximum number of network interface we can listen on */
#define MAX_IF_ADDR 8
#endif

129
minissdpd/daemonize.c Normal file
View File

@ -0,0 +1,129 @@
/* $Id: daemonize.c,v 1.12 2011/05/27 09:35:02 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include "daemonize.h"
#include "config.h"
#ifndef USE_DAEMON
int
daemonize(void)
{
int pid, i;
switch(fork())
{
/* fork error */
case -1:
perror("fork()");
exit(1);
/* child process */
case 0:
/* obtain a new process group */
if( (pid = setsid()) < 0)
{
perror("setsid()");
exit(1);
}
/* close all descriptors */
for (i=getdtablesize();i>=0;--i) close(i);
i = open("/dev/null", O_RDWR); /* open stdin */
dup(i); /* stdout */
dup(i); /* stderr */
umask(027);
chdir("/"); /* chdir to /tmp ? */
return pid;
/* parent process */
default:
exit(0);
}
}
#endif
int
writepidfile(const char * fname, int pid)
{
char pidstring[16];
int pidstringlen;
int pidfile;
if(!fname || (strlen(fname) == 0))
return -1;
if( (pidfile = open(fname, O_WRONLY|O_CREAT, 0644)) < 0)
{
syslog(LOG_ERR, "Unable to open pidfile for writing %s: %m", fname);
return -1;
}
pidstringlen = snprintf(pidstring, sizeof(pidstring), "%d\n", pid);
if(pidstringlen <= 0)
{
syslog(LOG_ERR,
"Unable to write to pidfile %s: snprintf(): FAILED", fname);
close(pidfile);
return -1;
}
else
{
if(write(pidfile, pidstring, pidstringlen) < 0)
syslog(LOG_ERR, "Unable to write to pidfile %s: %m", fname);
}
close(pidfile);
return 0;
}
int
checkforrunning(const char * fname)
{
char buffer[64];
int pidfile;
pid_t pid;
if(!fname || (strlen(fname) == 0))
return -1;
if( (pidfile = open(fname, O_RDONLY)) < 0)
return 0;
memset(buffer, 0, 64);
if(read(pidfile, buffer, 63))
{
if( (pid = atol(buffer)) > 0)
{
if(!kill(pid, 0))
{
close(pidfile);
return -2;
}
}
}
close(pidfile);
return 0;
}

35
minissdpd/daemonize.h Normal file
View File

@ -0,0 +1,35 @@
/* $Id: daemonize.h,v 1.6 2008/01/29 13:04:46 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef __DAEMONIZE_H__
#define __DAEMONIZE_H__
#include "config.h"
#ifndef USE_DAEMON
/* daemonize()
* "fork" to background, detach from terminal, etc...
* returns: pid of the daemon, exits upon failure */
int
daemonize(void);
#endif
/* writepidfile()
* write the pid to a file */
int
writepidfile(const char * fname, int pid);
/* checkforrunning()
* check for another instance running
* returns: 0 only instance
* -1 invalid filename
* -2 another instance running */
int
checkforrunning(const char * fname);
#endif

153
minissdpd/ifacewatch.c Normal file
View File

@ -0,0 +1,153 @@
/* $Id: ifacewatch.c,v 1.2 2011/07/30 13:10:05 nanard Exp $ */
/* MiniUPnP project
* (c) 2011 Thomas Bernard
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include "config.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#else /* __linux__ */
#include <net/route.h>
#endif
#include <syslog.h>
#include "openssdpsocket.h"
int
OpenAndConfInterfaceWatchSocket(void)
{
int s;
#ifdef __linux__
struct sockaddr_nl addr;
s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
#else /* __linux__*/
/*s = socket(PF_ROUTE, SOCK_RAW, AF_INET);*/
s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
/* The family parameter may be AF_UNSPEC which will provide routing informa-
* tion for all address families, or can be restricted to a specific address
* family by specifying which one is desired. There can be more than one
* routing socket open per system. */
#endif
if(s < 0) {
syslog(LOG_ERR, "OpenAndConfInterfaceWatchSocket socket: %m");
return -1;
}
#ifdef __linux__
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
syslog(LOG_ERR, "bind(netlink): %m");
close(s);
return -1;
}
#endif
return s;
}
/**
* Process the message and add/drop multicast membership if needed
*/
int
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
int n_if_addr, const char * * if_addr)
{
ssize_t len;
int i;
char buffer[4096];
#ifdef __linux__
struct iovec iov;
struct msghdr hdr;
struct nlmsghdr *nlhdr;
struct ifaddrmsg *ifa;
iov.iov_base = buffer;
iov.iov_len = sizeof(buffer);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
len = recvmsg(s, &hdr, 0);
if(len < 0) {
syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
return -1;
}
for(nlhdr = (struct nlmsghdr *)buffer;
NLMSG_OK(nlhdr, len);
nlhdr = NLMSG_NEXT(nlhdr, len)) {
syslog(LOG_DEBUG, "nlmsg_type=%d", nlhdr->nlmsg_type);
if(nlhdr->nlmsg_type == NLMSG_DONE)
break;
if(nlhdr->nlmsg_type == RTM_NEWADDR) {
ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR index=%d", ifa->ifa_index);
for(i = 0; i < n_if_addr; i++) {
if(ifa->ifa_index == if_nametoindex(if_addr[i])) {
AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 0);
break;
}
}
} else if(nlhdr->nlmsg_type == RTM_DELADDR) {
ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR index=%d", ifa->ifa_index);
for(i = 0; i < n_if_addr; i++) {
if(ifa->ifa_index == if_nametoindex(if_addr[i])) {
AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 1);
break;
}
}
}
}
#else /* __linux__ */
struct rt_msghdr * rtm;
struct ifa_msghdr * ifam;
len = recv(s, buffer, sizeof(buffer), 0);
if(len < 0) {
syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
return -1;
}
rtm = (struct rt_msghdr *)buffer;
switch(rtm->rtm_type) {
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)buffer;
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR index=%d", ifam->ifam_index);
for(i = 0; i < n_if_addr; i++) {
if(ifam->ifam_index == if_nametoindex(if_addr[i])) {
AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 0);
break;
}
}
break;
case RTM_DELADDR:
ifam = (struct ifa_msghdr *)buffer;
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR index=%d", ifam->ifam_index);
for(i = 0; i < n_if_addr; i++) {
if(ifam->ifam_index == if_nametoindex(if_addr[i])) {
/* I dont think it is useful */
/*AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 1);*/
break;
}
}
break;
default:
syslog(LOG_DEBUG, "rtm->rtm_type=%d", rtm->rtm_type);
}
#endif
return 0;
}

18
minissdpd/ifacewatch.h Normal file
View File

@ -0,0 +1,18 @@
/* $Id: ifacewatch.h,v 1.1 2011/07/29 15:21:13 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef __IFACEWATCH_H__
#define __IFACEWATCH_H__
int
OpenAndConfInterfaceWatchSocket(void);
int
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
int n_if_addr, const char * * if_addr);
#endif

79
minissdpd/listifaces.c Normal file
View File

@ -0,0 +1,79 @@
/* $Id: listifaces.c,v 1.4 2007/09/23 16:59:02 nanard Exp $ */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void printhex(const unsigned char * p, int n)
{
int i;
while(n>0)
{
for(i=0; i<16; i++)
printf("%02x ", p[i]);
printf("| ");
for(i=0; i<16; i++)
{
putchar((p[i]>=32 && p[i]<127)?p[i]:'.');
}
printf("\n");
p+=16;
n -= 16;
}
}
void listifaces()
{
struct ifconf ifc;
char * buf = 0;
int buflen = sizeof(struct ifreq)*20;
/*[sizeof(struct ifreq)*8];*/
int s, i;
int j;
char saddr[256/*INET_ADDRSTRLEN*/];
/*s = socket(PF_INET, SOCK_DGRAM, 0);*/
s = socket(AF_INET, SOCK_DGRAM, 0);
do {
buflen += buflen;
buf = realloc(buf, buflen);
ifc.ifc_len = buflen;
ifc.ifc_buf = (caddr_t)buf;
if(ioctl(s, SIOCGIFCONF, &ifc) < 0)
{
perror("ioctl");
close(s);
free(buf);
return;
}
printf("%d - %d - %d\n", buflen, ifc.ifc_len, (int)sizeof(struct ifreq));
printf(" %d\n", IFNAMSIZ);
printf(" %d %d\n", (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) );
} while(buflen == ifc.ifc_len);
printhex((const unsigned char *)ifc.ifc_buf, ifc.ifc_len);
j = 0;
for(i=0; i<ifc.ifc_len; /*i += sizeof(struct ifreq)*/)
{
//const struct ifreq * ifrp = &(ifc.ifc_req[j]);
const struct ifreq * ifrp = (const struct ifreq *)(buf + i);
i += sizeof(ifrp->ifr_name) + 16;//ifrp->ifr_addr.sa_len;
/*inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr), saddr, sizeof(saddr));*/
saddr[0] = '\0';
inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr));
printf("%2d %d %d %s %s\n", j, ifrp->ifr_addr.sa_family, -1/*ifrp->ifr_addr.sa_len*/, ifrp->ifr_name, saddr);
j++;
}
free(buf);
close(s);
}
int main(int argc, char * * argv)
{
listifaces();
return 0;
}

36
minissdpd/minissdpd.1 Normal file
View File

@ -0,0 +1,36 @@
.TH "minissdpd" 1
.SH NAME
minissdpd \- daemon keeping track of UPnP devices up
.SH SYNOPSIS
.B minissdpd
[-d] [-s socket] [-p pidfile] -i address [-i address] ...
.SH DESCRIPTION
minissdpd listen for SSDP traffic and keeps track
of what are the UPnP devices up on the network.
The list of the UPnP devices is accessed by programs
looking for devices, skipping the UPnP discovery process.
.SH OPTIONS
.TP
.B \-d
debug : do not go to background, output messages to console
and do not filter out low priority messages.
.TP
.B \-6
IPv6 : Enable IPv6 in addition to IPv4.
.TP
.B \-s socket
path of the unix socket open for communicating with other processes.
By default /var/run/minissdpd.sock is used.
.TP
.B \-p pidfile
path of the file where pid is written at startup.
By default /var/run/minissdpd.pid is used.
.TP
.B \-i interface
name or IP address of the interface used to listen to SSDP packets
comming on port 1900, multicast address 239.255.255.250.
.SH "SEE ALSO"
miniupnpd(1) miniupnpc(3)
.SH BUGS
No known bugs.

1081
minissdpd/minissdpd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
#!/bin/sh
# $Id: minissdpd.init.d.script,v 1.2 2007/09/23 17:46:57 nanard Exp $
# MiniUPnP project
# author: Thomas Bernard
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
MINISSDPD=/usr/sbin/minissdpd
PIDFILE=/var/run/minissdpd.pid
# get default interface
IF=`route | grep default |awk -- '{ print $8 }'`
ARGS="-i `ifconfig $IF|grep 'inet adr'|sed 's/.\+inet adr:\([0-9.]\+\).\+/\1/'`"
test -f $MINISSDPD || exit 0
. /lib/lsb/init-functions
case "$1" in
start) log_daemon_msg "Starting minissdpd" "minissdpd"
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $MINISSDPD -- $ARGS $LSBNAMES
log_end_msg $?
;;
stop) log_daemon_msg "Stopping minissdpd" "minissdpd"
start-stop-daemon --stop --quiet --pidfile $PIDFILE
log_end_msg $?
;;
restart|reload|force-reload)
log_daemon_msg "Restarting minissdpd" "minissdpd"
start-stop-daemon --stop --retry 5 --quiet --pidfile $PIDFILE
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $MINISSDPD -- $ARGS $LSBNAMES
log_end_msg $?
;;
*) log_action_msg "Usage: /etc/init.d/minissdpd {start|stop|restart|reload|force-reload}"
exit 2
;;
esac
exit 0

221
minissdpd/openssdpsocket.c Normal file
View File

@ -0,0 +1,221 @@
/* $Id: openssdpsocket.c,v 1.7 2011/07/30 13:10:06 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include "config.h"
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <syslog.h>
#include "openssdpsocket.h"
/* SSDP ip/port */
#define SSDP_PORT (1900)
#define SSDP_MCAST_ADDR ("239.255.255.250")
/* Link Local and Site Local SSDP IPv6 multicast addresses */
#define LL_SSDP_MCAST_ADDR ("FF02::C")
#define SL_SSDP_MCAST_ADDR ("FF05::C")
/**
* Get the IPv4 address from a string
* representing the address or the interface name
*/
static in_addr_t
GetIfAddrIPv4(const char * ifaddr)
{
in_addr_t addr;
int s;
struct ifreq ifr;
int ifrlen;
/* let's suppose ifaddr is a IPv4 address
* such as 192.168.1.1 */
addr = inet_addr(ifaddr);
if(addr != INADDR_NONE)
{
return addr;
}
/* let's suppose the ifaddr was in fact an interface name
* such as eth0 */
s = socket(PF_INET, SOCK_DGRAM, 0);
if(s < 0)
{
syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m");
return INADDR_NONE;
}
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, ifaddr, IFNAMSIZ);
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
{
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
close(s);
return INADDR_NONE;
}
syslog(LOG_DEBUG, "GetIfAddrIPv4(%s) = %s", ifaddr,
inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
close(s);
return addr;
}
/**
* Add the multicast membership for SSDP on the interface
* @param s the socket
* @param ifaddr the IPv4 address or interface name
* @param ipv6 IPv6 or IPv4
* return -1 on error, 0 on success */
int
AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
{
struct ip_mreq imr; /* Ip multicast membership */
#ifdef ENABLE_IPV6
struct ipv6_mreq mr;
unsigned int ifindex;
#endif
#ifdef ENABLE_IPV6
if(ipv6)
{
ifindex = if_nametoindex(ifaddr);
memset(&mr, 0, sizeof(mr));
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
mr.ipv6mr_interface = ifindex;
if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
&mr, sizeof(struct ipv6_mreq)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
ifaddr);
return -1;
}
inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
&mr, sizeof(struct ipv6_mreq)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
ifaddr);
return -1;
}
}
else
{
#endif
/* setting up imr structure */
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
/*imr.imr_interface.s_addr = inet_addr(ifaddr);*/
imr.imr_interface.s_addr = GetIfAddrIPv4(ifaddr);
if(imr.imr_interface.s_addr == INADDR_NONE)
{
syslog(LOG_ERR, "no IPv4 address for interface %s",
ifaddr);
return -1;
}
if (setsockopt(s, IPPROTO_IP, drop ? IP_DROP_MEMBERSHIP : IP_ADD_MEMBERSHIP,
(void *)&imr, sizeof(struct ip_mreq)) < 0)
{
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
ifaddr);
return -1;
}
#ifdef ENABLE_IPV6
}
#endif
return 0;
}
int
OpenAndConfSSDPReceiveSocket(int n_listen_addr,
const char * * listen_addr,
int ipv6)
{
int s;
#ifdef ENABLE_IPV6
int on = 1;
struct sockaddr_storage sockname;
#else
struct sockaddr_in sockname;
#endif
socklen_t sockname_len;
#ifdef ENABLE_IPV6
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
#else
if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
#endif
{
syslog(LOG_ERR, "socket(udp): %m");
return -1;
}
#ifdef ENABLE_IPV6
memset(&sockname, 0, sizeof(struct sockaddr_storage));
if(ipv6)
{
#ifdef IPV6_V6ONLY
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&on, sizeof(on)) < 0)
{
syslog(LOG_WARNING, "setsockopt(IPV6_V6ONLY): %m");
}
#endif
struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&sockname;
sa->sin6_family = AF_INET6;
sa->sin6_port = htons(SSDP_PORT);
sa->sin6_addr = in6addr_any;
sockname_len = sizeof(struct sockaddr_in6);
}
else
{
struct sockaddr_in * sa = (struct sockaddr_in *)&sockname;
sa->sin_family = AF_INET;
sa->sin_port = htons(SSDP_PORT);
sa->sin_addr.s_addr = htonl(INADDR_ANY);
sockname_len = sizeof(struct sockaddr_in);
}
#else
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(SSDP_PORT);
/* NOTE : it seems it doesnt work when binding on the specific address */
/*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
/*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/
sockname_len = sizeof(struct sockaddr_in);
#endif
if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
{
syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
close(s);
return -1;
}
while(n_listen_addr>0)
{
n_listen_addr--;
if(AddDropMulticastMembership(s, listen_addr[n_listen_addr], ipv6, 0) < 0)
{
syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
ipv6 ? 6 : 4,
listen_addr[n_listen_addr] );
}
}
return s;
}

View File

@ -0,0 +1,34 @@
/* $Id: openssdpsocket.h,v 1.4 2011/07/29 15:21:13 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef __OPENSSDPSOCKET_H__
#define __OPENSSDPSOCKET_H__
/**
* Open a socket and configure it for receiving SSDP packets
*
* @param n_listen_addr size of listen_addr array
* @param listen_addr array of address (or interface names) to listen
* @param ipv6 open INET6 or INET socket
* @return socket
*/
int
OpenAndConfSSDPReceiveSocket(int n_if_addr,
const char * * if_addr,
int ipv6);
/**
* Add or Drop the multicast membership for SSDP on the interface
* @param s the socket
* @param ifaddr the IPv4 address or interface name
* @param ipv6 IPv6 or IPv4
* @param drop 0 to add, 1 to drop
* return -1 on error, 0 on success */
int
AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop);
#endif

View File

@ -0,0 +1,30 @@
/* $Id: testcodelength.c,v 1.2 2011/06/17 23:05:00 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2008 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <stdio.h>
#include "codelength.h"
int main(int argc, char * * argv)
{
unsigned char buf[256];
unsigned char * p;
long i, j;
for(i = 1; i < 1000000000; i *= 2) {
/* encode i, decode to j */
printf("%ld ", i);
p = buf;
CODELENGTH(i, p);
p = buf;
DECODELENGTH(j, p);
if(i != j) {
fprintf(stderr, "Error ! encoded %ld, decoded %ld.\n", i, j);
return 1;
}
}
printf("Test succesful\n");
return 0;
}

96
minissdpd/testminissdpd.c Normal file
View File

@ -0,0 +1,96 @@
/* $Id: testminissdpd.c,v 1.6 2007/12/19 14:49:30 nanard Exp $ */
/* Project : miniupnp
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
* copyright (c) 2005-2007 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while(*(p++)&0x80);
void printresponse(const unsigned char * resp, int n)
{
int i, l;
unsigned int nresp;
const unsigned char * p;
for(i=0; i<n; i++)
printf("%02x ", resp[i]);
printf("\n");
nresp = resp[0];
p = resp + 1;
for(i = 0; i < nresp; i++) {
/*l = *(p++);*/
DECODELENGTH(l, p);
printf("%d - %.*s\n", i, l, p);
p += l;
/*l = *(p++);*/
DECODELENGTH(l, p);
printf(" %.*s\n", l, p);
p += l;
/*l = *(p++);*/
DECODELENGTH(l, p);
printf(" %.*s\n", l, p);
p += l;
}
}
#define SENDCOMMAND(command, size) write(s, command, size); \
printf("Command written type=%u\n", (unsigned)command[0]);
/* test program for minissdpd */
int
main(int argc, char * * argv)
{
char command1[] = "\x01\x00urn:schemas-upnp-org:device:InternetGatewayDevice";
char command2[] = "\x02\x00uuid:fc4ec57e-b051-11db-88f8-0060085db3f6::upnp:rootdevice";
char command3[] = { 0x03, 0x00 };
struct sockaddr_un addr;
int s;
int i;
unsigned char buf[2048];
ssize_t n;
const char * sockpath = "/var/run/minissdpd.sock";
for(i=0; i<argc-1; i++) {
if(0==strcmp(argv[i], "-s"))
sockpath = argv[++i];
}
command1[1] = sizeof(command1) - 3;
command2[1] = sizeof(command2) - 3;
s = socket(AF_UNIX, SOCK_STREAM, 0);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
fprintf(stderr, "connecting to %s\n", addr.sun_path);
perror("connect");
return 1;
}
printf("Connected.\n");
SENDCOMMAND(command1, sizeof(command1) - 1);
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
SENDCOMMAND(command2, sizeof(command2) - 1);
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
SENDCOMMAND(command3, sizeof(command3));
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
close(s);
return 0;
}

68
minissdpd/upnputils.c Normal file
View File

@ -0,0 +1,68 @@
/* $Id: upnputils.c,v 1.3 2011/05/20 09:42:23 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef AF_LINK
#include <net/if_dl.h>
#endif
#include "upnputils.h"
int
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
{
char buffer[64];
unsigned short port = 0;
int n = -1;
switch(addr->sa_family)
{
case AF_INET6:
inet_ntop(addr->sa_family,
&((struct sockaddr_in6 *)addr)->sin6_addr,
buffer, sizeof(buffer));
port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
n = snprintf(str, size, "[%s]:%hu", buffer, port);
break;
case AF_INET:
inet_ntop(addr->sa_family,
&((struct sockaddr_in *)addr)->sin_addr,
buffer, sizeof(buffer));
port = ntohs(((struct sockaddr_in *)addr)->sin_port);
n = snprintf(str, size, "%s:%hu", buffer, port);
break;
#ifdef AF_LINK
case AF_LINK:
{
struct sockaddr_dl * sdl = (struct sockaddr_dl *)addr;
n = snprintf(str, size, "index=%hu type=%d %s",
sdl->sdl_index, sdl->sdl_type,
link_ntoa(sdl));
}
break;
#endif
default:
n = snprintf(str, size, "unknown address family %d", addr->sa_family);
#if 0
n = snprintf(str, size, "unknown address family %d "
"%02x %02x %02x %02x %02x %02x %02x %02x",
addr->sa_family,
addr->sa_data[0], addr->sa_data[1], (unsigned)addr->sa_data[2], addr->sa_data[3],
addr->sa_data[4], addr->sa_data[5], (unsigned)addr->sa_data[6], addr->sa_data[7]);
#endif
}
return n;
}

20
minissdpd/upnputils.h Normal file
View File

@ -0,0 +1,20 @@
/* $Id: upnputils.h,v 1.1 2011/05/15 08:58:41 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef __UPNPUTILS_H__
#define __UPNPUTILS_H__
/**
* convert a struct sockaddr to a human readable string.
* [ipv6]:port or ipv4:port
* return the number of characters used (as snprintf)
*/
int
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size);
#endif