Adding miniupnpd
This commit is contained in:
parent
c183a72c46
commit
0d96346588
|
@ -0,0 +1,717 @@
|
|||
$Id: Changelog.txt,v 1.240 2011/07/30 13:14:34 nanard Exp $
|
||||
|
||||
2011/07/30:
|
||||
netfilter : Added a tiny_nf_nat.h file to compile with iptables
|
||||
installed headers.
|
||||
include xtables.h instead of iptables.h
|
||||
|
||||
VERSION 1.6 : released the 2011/07/25
|
||||
|
||||
2011/07/25:
|
||||
Update doc for version 1.6
|
||||
|
||||
2011/07/15:
|
||||
Fixing code with MULTIPLE_EXTERNAL_IP defined.
|
||||
|
||||
2011/06/27:
|
||||
IPv6 support for UPnP events.
|
||||
Security checks in UPnP events.
|
||||
|
||||
2011/06/22:
|
||||
Remote host for GetListOfPortMappings
|
||||
Remote host support for ipfw (tested on Mac OS X)
|
||||
|
||||
2011/06/20:
|
||||
support for iptables-1.4.11.1
|
||||
|
||||
2011/06/18:
|
||||
Remote host support for pf version
|
||||
|
||||
2011/06/04:
|
||||
Supporting RemoteHost (mandatory in IGD v2)
|
||||
|
||||
2011/06/03:
|
||||
Enabling events by default
|
||||
|
||||
2011/06/01:
|
||||
Fixing Timeout missing in SUBSCRIBE renewal responses
|
||||
(thanks to Pranesh Kulkarni)
|
||||
Added comments about changes between IGD v1 and IGD v2
|
||||
|
||||
2011/05/28:
|
||||
Description and leaseduration kept in ipfw version of the code.
|
||||
Fixing ipfw code after testing under Mac OS X 10.6.7 (darwin 10.7.0)
|
||||
|
||||
2011/05/27:
|
||||
Finishing and testing LeaseDuration support under OpenBSD.
|
||||
Changing NAT-PMP port mapping lifetime support to match
|
||||
lease duration support.
|
||||
NAT-PMP address change announce broadcasted to both port
|
||||
5350 and 5351 to be compatible with client following the
|
||||
version of NAT PMP specification from 2008 or earlier.
|
||||
writepidfile() Overwrite file if already existing
|
||||
|
||||
2011/05/26:
|
||||
fix in linux/getifstats.c.
|
||||
See http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2212
|
||||
Implementation of LeaseDuration support.
|
||||
|
||||
2011/05/23:
|
||||
added get_wan_connection_status_str()
|
||||
|
||||
2011/05/20:
|
||||
adding ifacewatcher thanks to Alexey Osipov
|
||||
GET /DP.xml is now available. The description has to be completed.
|
||||
|
||||
2011/05/19:
|
||||
Add getconnstatus.c/.h. Dont always have ConnectionStatus to "Connected"
|
||||
Events for WANIPv6FirewallControll
|
||||
|
||||
2011/05/16:
|
||||
patches for gentoo linux.
|
||||
generation of the DeviceProtection service description.
|
||||
|
||||
2011/05/15:
|
||||
Making the SSDP receiving socket work in IPv6 !
|
||||
|
||||
2011/05/14:
|
||||
Support for HTTP in both IPv6 and IPv4.
|
||||
IPv6 for SSDP receiving socket.
|
||||
|
||||
2011/05/13:
|
||||
add new options in genconfig.sh (IGD_V2, ENABLE_DP_SERVICE)
|
||||
add global vars ipv6fc_firewall_enabled and ipv6fc_inbound_pinhole_allowed
|
||||
have MACROS for magical values in upnpdescgen.c, add eventing vars for WanIPv6FirewallControl.
|
||||
applied 0001-Cosmetic-changes.patch(see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=764)
|
||||
applied 0002-Remove-lan-addresses-limit-by-changing-storage-type-.patch
|
||||
replaced some of the urn:schemas-upnp-org:device:* literal strings by macros.
|
||||
adding some support for IP v6. #define ENABLE_IPV6
|
||||
added -fno-strict-aliasing to compile options.
|
||||
|
||||
2011/05/09:
|
||||
updating upnp descriptions for IGDv2
|
||||
|
||||
2011/05/07:
|
||||
Adding WANIPv6FirewallContro to upnp description
|
||||
|
||||
2011/04/30:
|
||||
adding a UPNP_STRICT config macro. Use it now for checking RemoteHost.
|
||||
ENABLE_6FC_SERVICE : add the implementations of WANIPv6FirewallControl actions
|
||||
|
||||
2011/04/11:
|
||||
preparing getifaddr() for IP v6
|
||||
preparing SSDP stuff for IP v6. Trying to conform to UDA v1.1
|
||||
|
||||
2011/03/09:
|
||||
Some modifications thanks to Daniel Dickinson to improve OpenWRT
|
||||
build.
|
||||
Fixed some warnings.
|
||||
|
||||
2011/03/03:
|
||||
Added code to generate devices/services descriptions for IGD v2
|
||||
(to be continued)
|
||||
|
||||
2011/03/02:
|
||||
improved netfilter/delete_redirect_and_filter_rules() in order
|
||||
to remove the right filter rule, even if it has another index than
|
||||
the nat rule.
|
||||
|
||||
2011/03/01:
|
||||
clean up an fixes to make netfilter/testiptcrdr compile
|
||||
|
||||
2011/02/21:
|
||||
Make "Makefile" work under Mac OS X with bsdmake.
|
||||
added get_portmappings_in_range() in ipfwrdr.c
|
||||
|
||||
2011/02/07:
|
||||
added get_portmappings_in_range() / upnp_get_portmappings_in_range()
|
||||
|
||||
2011/02/06:
|
||||
Implementation of GetListOfPortMappings
|
||||
|
||||
2011/01/27:
|
||||
Reverting "fixes" done in linux/iptables code the 2010/09/27.
|
||||
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=741
|
||||
|
||||
2011/01/04:
|
||||
added MINIUPNPD_VERSION in config.h. Taken from VERSION file.
|
||||
|
||||
VERSION 1.5 : released the 2011/01/01
|
||||
|
||||
2011/01/01:
|
||||
Started to implement some of the new methods from WANIPConnection v2
|
||||
|
||||
2010/09/27:
|
||||
Some fixes in the linux/iptables code when
|
||||
miniupnpd_nat_chain <> miniupnpd_forward_chain
|
||||
|
||||
2010/09/21:
|
||||
Patch to support nfqueue thanks to Colin McFarlane
|
||||
|
||||
2010/08/07:
|
||||
Update Mac OS X / ipfw stuff from Jardel Weyrich
|
||||
Fix in Makefile.linux for x86_64
|
||||
|
||||
2010/05/06:
|
||||
Bugfix un CleanNATPMPRules() : see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=640
|
||||
|
||||
2010/03/14:
|
||||
Fixing natpmp sockets.
|
||||
|
||||
2010/03/08:
|
||||
Fix Makefile.linux to compile properly under Mandriva/rh/Fedora with
|
||||
Iptables >= 1.4.3
|
||||
Workaround for bad uptime when started with a bad time set.
|
||||
|
||||
2010/03/07:
|
||||
Tried to make a OpenBSD version 4.7 compatible code... still some
|
||||
issues.
|
||||
|
||||
2010/03/06:
|
||||
updates to testobsdrdr
|
||||
|
||||
2010/03/03:
|
||||
-lip4tc in Makefile.linux.
|
||||
|
||||
2010/02/15:
|
||||
some more error handling in set_startup_time()
|
||||
silencing some warnings
|
||||
|
||||
2010/01/14:
|
||||
Open Several sockets for NAT-PMP to make sure the source address
|
||||
of NAT-PMP replies is right.
|
||||
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=609
|
||||
|
||||
2009/12/31:
|
||||
miniupnpdctl now output command line arguments.
|
||||
added a -h option to get help. improved help.
|
||||
|
||||
2009/12/22:
|
||||
using PRIu64 format to printf u_int64_t
|
||||
Fixing calls to get_redirect_rule_by_index() : ifname should be initialized.
|
||||
Add header lines to miniupnpdctl output
|
||||
|
||||
2009/11/06:
|
||||
implementing sending of ip address change notification when receiving
|
||||
the signal SIGUSR1
|
||||
|
||||
VERSION 1.4 : released the 2009/10/30
|
||||
|
||||
2009/10/10:
|
||||
Integrate IPfilter patch from Roy Marples.
|
||||
Fix Netfilter code for old netfilter :
|
||||
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=584
|
||||
trim the description string in reload_from_lease_file()
|
||||
|
||||
2009/09/21:
|
||||
Fixing unclosed raw sockets bug with netfilter code.
|
||||
|
||||
2009/09/04:
|
||||
Fixes in ipf code thanks to Roy Marples
|
||||
Enable DragonFly BSD Support thanks to Roy Marples.
|
||||
Allow packager to define default location of config file via CFLAGS
|
||||
Respect $DESTDIR when installing
|
||||
|
||||
2009/08/20:
|
||||
Adding some support for MacOS X and IPFW
|
||||
SO_REUSEADDR in minissdp.c for SSDP listening socket
|
||||
|
||||
2009/06/05:
|
||||
unlink lease file in reload_from_lease_file()
|
||||
|
||||
2009/05/16:
|
||||
Fixed a buffer overflow in ProcessSSDPRequest()
|
||||
|
||||
2009/05/11:
|
||||
improving genconfig.sh for NetBSD : detecting use of pf or ipf
|
||||
|
||||
VERSION 1.3 :
|
||||
2009/04/17:
|
||||
working support for iptables >= 1.4.3
|
||||
|
||||
2009/04/13:
|
||||
work to support iptables-1.4.3 and up
|
||||
|
||||
2009/04/10:
|
||||
fix in upnpevents_removeSubscriber()
|
||||
|
||||
2009/02/14:
|
||||
added reload_from_lease_file()
|
||||
|
||||
2009/02/13:
|
||||
Changes in upnpdescgen.c to allow to remove empty elements
|
||||
strcasecmp instead of strcmp on path comparaisons to allow
|
||||
bugged clients to work
|
||||
|
||||
2009/01/29:
|
||||
Some minor changes to Makefile
|
||||
improving Makefile.linux in order to build with iptables not properly
|
||||
installed on the system.
|
||||
|
||||
2009/01/23:
|
||||
Fixing upnpevents thanks to Justin Maggard
|
||||
|
||||
2008/10/15:
|
||||
getifstats() return -1 when supplied with bad arguments
|
||||
|
||||
2008/10/11:
|
||||
Fixed NAT-PMP response when IP not allocated to external interface
|
||||
|
||||
2008/10/09:
|
||||
adding testgetifaddr
|
||||
Reporting Unconnected status when the "external interface" has
|
||||
no IP address assigned. Also added some comments
|
||||
|
||||
VERSION 1.2 :
|
||||
|
||||
2008/10/07:
|
||||
updating docs
|
||||
|
||||
2008/10/06:
|
||||
MiniUPnPd is now able to use MiniSSDPd to manage SSDP M-SEARCH answering
|
||||
|
||||
2008/10/03:
|
||||
You can now let miniupnpd choose itself the HTTP port used.
|
||||
|
||||
2008/10/01:
|
||||
Improvements in genconfig.sh for detecting ipf or pf (under FreeBSD)
|
||||
and improve debian/ubuntu stuff.
|
||||
custom chain name patch from :
|
||||
http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=493
|
||||
|
||||
2008/08/24:
|
||||
added USE_IFNAME_IN_RULES macro that can be disabled in order to
|
||||
remove interface name from rules.
|
||||
|
||||
2008/07/10:
|
||||
Fixed compilation without ENABLE_L3F_SERVICE
|
||||
|
||||
2008/04/27:
|
||||
correct UNSUBSCRIBE processing
|
||||
|
||||
2008/04/25(bis):
|
||||
changed iptables_removeall.sh and iptables_init.sh in order
|
||||
to remove IP from the rules
|
||||
|
||||
VERSION 1.1 :
|
||||
|
||||
2008/04/25:
|
||||
Eventing is allmost completly implemented
|
||||
|
||||
2008/04/24:
|
||||
Correct event handling ?
|
||||
|
||||
2008/04/08:
|
||||
enabling tag in PF rules. quick can be set off.
|
||||
|
||||
2008/03/13:
|
||||
implementing event notify
|
||||
|
||||
2008/03/11:
|
||||
fixing a command line parsing error
|
||||
|
||||
2008/03/09:
|
||||
optimisations in upnpsoap.c
|
||||
|
||||
2008/03/08:
|
||||
optimizing upnpsoap.c for size
|
||||
|
||||
2008/03/06:
|
||||
Worked on the Eventing : generating XML event notifications
|
||||
Send initial notification after subscribe
|
||||
Improved pretty print of testupnpdescgen
|
||||
Reduced Memory usage of upnpdescgen
|
||||
fixed a small bug in the description
|
||||
|
||||
2008/03/03:
|
||||
Fixed miniupnpd.c for compiling without natpmp support
|
||||
fixed presentationURL not there with L3F
|
||||
fixing lease file creation/modification
|
||||
|
||||
2008/02/25:
|
||||
Rewrite of Send501() and Send404()
|
||||
More work on events
|
||||
genconfig.sh autodetects pf/ipf
|
||||
|
||||
2008/02/24:
|
||||
Started to implement UPnP Events. do NOT use it at the moment !
|
||||
|
||||
2008/02/21:
|
||||
Added support for the Layer3Forwarding Service
|
||||
added init_redirect() and shutdown_redirect() functions
|
||||
|
||||
2008/02/20:
|
||||
Removed Ext: HTTP header when useless
|
||||
enabled the dummy service by default to please windows XP !
|
||||
|
||||
2008/02/07:
|
||||
upnp_enable patch by Nikos Mavrogiannopoulos.
|
||||
lease_file patch by Nikos Mavrogiannopoulos.
|
||||
|
||||
2008/01/29:
|
||||
some changes to Makefile.openwrt
|
||||
use daemon() - daemonize() is still available for systems lacking daemon()
|
||||
|
||||
VERSION 1.0 :
|
||||
2008/01/27:
|
||||
moved lan_addr to upnpglobalvars.h/.c
|
||||
Adding experimental multiple external IP support.
|
||||
|
||||
2008/01/22:
|
||||
removed dummy service from description to improve compatibility
|
||||
with emule client
|
||||
Add "secure mode". put runtime flags in the same variable
|
||||
|
||||
2008/01/14:
|
||||
Fixed a bug in options.c for the parsing of empty lines.
|
||||
|
||||
2008/01/03:
|
||||
Fixed CleanExpiredNATPMP()
|
||||
|
||||
2008/01/02:
|
||||
Adding a queue parameter for setting ALTQ in pf
|
||||
|
||||
2007/12/27:
|
||||
improving some stuff with the PF_ENABLE_FILTER_RULE.
|
||||
|
||||
2007/12/22:
|
||||
Adding a runtime option to enable/disable NAT-PMP
|
||||
|
||||
2007/12/20:
|
||||
Added a cache in linux getifstats(). Please enable by editing config.h
|
||||
|
||||
2007/12/14:
|
||||
Updating an existing NAT-PMP mapping now works
|
||||
|
||||
2007/12/13:
|
||||
NAT-PMP code now remove expired mappings
|
||||
TCP/UDP where swapped in NAT-PMP code
|
||||
|
||||
2007/12/04:
|
||||
Adding details to the error message for sendto(udp_notify)
|
||||
|
||||
2007/11/27:
|
||||
pf code doesn't generate filter rules by default anymore. The
|
||||
#ifdef PF_ENABLE_FILTER_RULES must be uncommented in config.h.
|
||||
|
||||
2007/11/02:
|
||||
moved some of the prototypes common to all firewalls to commonrdr.h
|
||||
Added functionalities to NAT-PMP
|
||||
|
||||
2007/11/01:
|
||||
Debugged NAT-PMP code
|
||||
|
||||
2007/10/28:
|
||||
Cleaning and improving NAT-PMP code
|
||||
|
||||
2007/10/25:
|
||||
improved the NAT-PMP experimental support
|
||||
updated README and INSTALL files
|
||||
|
||||
2007/10/24:
|
||||
Adding support for NAT-PMP (from apple !)
|
||||
|
||||
2007/10/11:
|
||||
Checking the commandline for errors.
|
||||
|
||||
2007/10/08:
|
||||
Improved the BSD/Solaris Makefile
|
||||
Merging last code from Darren Reed. Solaris/IPF should work now !
|
||||
added a man page.
|
||||
|
||||
2007/10/07:
|
||||
Adding Darren Reed code for ipf.
|
||||
|
||||
2007/10/06:
|
||||
Adding SunOS support thanks to Darren Reed.
|
||||
Reorganizing os/firewall dependent code thanks to Darren Reed.
|
||||
|
||||
2007/09/27:
|
||||
linux make install support PREFIX variable
|
||||
|
||||
2007/09/25:
|
||||
reorganizing LAN sockets/address to improve multi LAN support.
|
||||
SSDP announces are sent to all configured networks.
|
||||
SSDP responses are "customized" by subnetwork.
|
||||
|
||||
2007/09/24:
|
||||
prototype code to remove unused rules
|
||||
miniupnpdctl now display current rules
|
||||
synchronised add_filter_rule2() prototype between pf and netfilter code.
|
||||
|
||||
2007/09/19:
|
||||
Correctly filling the Cache-control header in SSDP packets
|
||||
|
||||
2007/08/28:
|
||||
update PFRULE_INOUT_COUNTS detection for FreeBSD
|
||||
|
||||
2007/08/27:
|
||||
update version in genconfig.sh
|
||||
do not error when a duplicate redirection is requested.
|
||||
|
||||
2007/07/16:
|
||||
really fixed the compilation bug with linux>=2.6.22
|
||||
|
||||
2007/07/04:
|
||||
fixed an error in options.c that prevented to use packet_log option
|
||||
|
||||
2007/07/03:
|
||||
improved genconfig.sh
|
||||
fixed a compilation bug with linux>=2.6.22
|
||||
|
||||
2007/06/22:
|
||||
added PFRULE_INOUT_COUNTS macro to enable separate in/out packet and
|
||||
bytes counts in pf for OpenBSD >= 3.8
|
||||
|
||||
2007/06/15:
|
||||
removed a possible racecondition in writepidfile()
|
||||
|
||||
2007/06/12:
|
||||
improved genconfig.sh : no more "echo -e", use lsb_release when available
|
||||
|
||||
2007/06/11:
|
||||
get_redirect_rule*() functions now return some statistics about
|
||||
rule usage (bytes and packets)
|
||||
|
||||
2007/06/07:
|
||||
Fixed the get_redirect_desc() in the linux/netfilter code
|
||||
|
||||
2007/06/05:
|
||||
Clean up init code in miniupnpd.c
|
||||
Added a syslog message in SoapError()
|
||||
|
||||
2007/06/04:
|
||||
Now store redirection descriptions in the linux/netfilter code
|
||||
|
||||
2007/05/21:
|
||||
Answers to SSDP M-SEARCH requests with ST: ssdp:all
|
||||
added make install to Makefile.linux
|
||||
|
||||
2007/05/10:
|
||||
Fixed a bug int the DeletePortMapping linux/netfilter implementation
|
||||
It was allways the 1st rule that was deleted.
|
||||
|
||||
2007/04/26:
|
||||
Fixed config.h.openwrt
|
||||
|
||||
2007/04/16:
|
||||
added something in the INSTALL file about the FreeBSD send(udp_notify)
|
||||
problem fix (allowing 239.0.0.0/8 explicitely in pf.conf)
|
||||
|
||||
2007/03/30:
|
||||
added setsockopt(s, SOL_SOCKET, SO_BROADCAST ...) for broadcasting
|
||||
socket
|
||||
|
||||
2007/03/17:
|
||||
Fixed filter rule under linux : it was using wrong port !
|
||||
thanks to Wesley W. Terpstra
|
||||
|
||||
2007/03/01:
|
||||
Moved some of the SSDP code from miniupnpd.c to minissdp.c
|
||||
|
||||
2007/02/28:
|
||||
creating miniupnpdctl
|
||||
|
||||
2007/02/26:
|
||||
use LOG_MINIUPNPD macro for openlog()
|
||||
simplify miniupndShutdown()
|
||||
|
||||
2007/02/09:
|
||||
improved genconfig.h
|
||||
Added stuff to change the pf rule "rdr" to "rdr pass"
|
||||
|
||||
2007/02/07:
|
||||
Corrected Bytes per seconds to bits per second.
|
||||
Ryan cleaned up comments and typos.
|
||||
Ryan cleaned up daemonize stuff.
|
||||
Ryan added possibility to configure model number and serial number
|
||||
|
||||
2007/01/30:
|
||||
ryan improved the robustness of most UPnP Soap methods
|
||||
I added a target in the Makefiles to properly generate an uuid using
|
||||
command line tools.
|
||||
Improved configuration file parsing.
|
||||
|
||||
2007/01/29:
|
||||
Adding uuid option in miniupnpd.conf
|
||||
|
||||
2007/01/27:
|
||||
Added upnppermissions stuff : adding some security to UPnP !
|
||||
fixed XML description thanks to Ryan Wagoner
|
||||
improved QueryStateVariable thanks to Ryan Wagoner
|
||||
|
||||
2007/01/22:
|
||||
use getifaddr() for each GetExtenalIPAddress() Call.
|
||||
We can change the ip during execution without pb
|
||||
|
||||
2007/01/17:
|
||||
Lots of code cleanup
|
||||
|
||||
2007/01/12:
|
||||
Fixed a nasty bug in the linux/netfilter version of get_filter_rule()
|
||||
|
||||
2007/01/11:
|
||||
Improved the handling of the miniupnpd.conf file.
|
||||
added -f option to choose which config file to read.
|
||||
|
||||
2007/01/10:
|
||||
Fixed potential bugs with ClearNameValueList()
|
||||
|
||||
2007/01/08:
|
||||
All by Ryan Wagoner :
|
||||
- coding style and comments cleanup
|
||||
- using now option file miniupnpd.conf
|
||||
|
||||
2007/01/03:
|
||||
changed "xx active incoming HTTP connections" msg
|
||||
|
||||
2007/01/02:
|
||||
Patch from Ryan Wagoner :
|
||||
- no need to open sockets if we can't set the error handlers
|
||||
- format the usage so it fits nicely on a standard size terminal
|
||||
- fix up log_err message so they have the same format and you know what
|
||||
they are related to
|
||||
- use same "white space" style throughout
|
||||
- on shutdown no need to continue if opening socket or setsockopt fails
|
||||
|
||||
2006/12/14:
|
||||
reduce amount of log lines (keeping the same information)
|
||||
|
||||
2006/12/07:
|
||||
Fixed Makefiles
|
||||
fixed typos in logs
|
||||
version 1.0-RC1 released
|
||||
|
||||
2006/12/02:
|
||||
moved strings from upnpdescgen.c to upnpdescstrings.h for
|
||||
easier modification
|
||||
Server: HTTP header now comes from a #define
|
||||
added a compilation-time generated config.h
|
||||
|
||||
2006/11/30:
|
||||
minixml updated. should have no impact
|
||||
Added support for presentationURL with -w switch
|
||||
implemented getifstats() for linux. Added testgetifstats program
|
||||
improved error handling in getifstats() BSD
|
||||
|
||||
2006/11/26:
|
||||
no need to have miniupnpc sources to compile miniupnpd.
|
||||
Makefile.openwrt updated
|
||||
Closing sockets on exit thanks to Ryan Wagoner
|
||||
|
||||
2006/11/23:
|
||||
now handling signal SIGINT
|
||||
setting HTTP socket with REUSEADDR thanks to Ryan Wagoner
|
||||
daemon now tested on a Linksys WRT54G device running OpenWRT !
|
||||
|
||||
2006/11/21:
|
||||
disabling rtableid in pf code.
|
||||
|
||||
2006/11/22:
|
||||
Also responds on M-SEARCH with the uuid
|
||||
|
||||
2006/11/20:
|
||||
gaining some space in upnpsoap.c
|
||||
|
||||
2006/11/19:
|
||||
Cleaning up code to comply with ANSI C89
|
||||
|
||||
2006/11/17:
|
||||
Linux version now deleting both nat and accept rules
|
||||
implemented -U option under Linux
|
||||
|
||||
2006/11/16:
|
||||
implemented delete_redirect_rule() for linux
|
||||
returning error 714 in DeletePortMapping() when needed
|
||||
|
||||
2006/11/12:
|
||||
The linux/netfilter version should now WORK !
|
||||
fix in the writepidfile() function. open with a mode !
|
||||
|
||||
2006/11/10:
|
||||
fixing the XML description generation for big endian machines
|
||||
working on the linux/netfilter port
|
||||
|
||||
2006/11/09:
|
||||
improved a lot the handling of HTTP error cases
|
||||
|
||||
2006/11/08:
|
||||
Tried to make the Makefile compatible with both BSDmake
|
||||
and GNUmake. It was hard because of $^ and $<
|
||||
|
||||
2006/11/07:
|
||||
Makefile compatible with BSD make
|
||||
make install target.
|
||||
getifstats.c compatible with both OpenBSD and FreeBSD.
|
||||
|
||||
2006/11/06:
|
||||
added getifstats.c for openBSD. May not work under FreeBSD ?
|
||||
now reports bytes/packets sent/received
|
||||
reporting bitrates
|
||||
possibility to report system uptime
|
||||
|
||||
2006/10/29:
|
||||
added a -L option to enable loggin (is off by default now).
|
||||
|
||||
2006/10/28:
|
||||
Patch by Ryan Wagoner to correct the XML description (was NewUpTime
|
||||
instead of NewUptime) and implement uptime.
|
||||
Trying to fix the memory leak. Added some comments
|
||||
added a -d option for debugging purpose
|
||||
Tnaks to valgrind (under linux!) I removed a small memory access error.
|
||||
|
||||
2006/10/27:
|
||||
Thanks to a patch sent by Michael van Tellingen, miniupnpd is
|
||||
now ignoring NOTIFY packets sent by other devices and is
|
||||
writing is own pid to /var/run/miniupnpd.pid
|
||||
|
||||
2006/10/23:
|
||||
Allways set sendEvents="no" in XML description (was causing
|
||||
pb with winXP as SUBSCRIBE is not implemented)
|
||||
|
||||
2006/10/22:
|
||||
added translation from hostname to IP in the AddPortMapping() method
|
||||
Thanks to Ryan Wagoner.
|
||||
|
||||
2006/10/18:
|
||||
Added an INSTALL file
|
||||
|
||||
2006/10/13:
|
||||
Added the possibility to change the notify interval
|
||||
|
||||
2006/09/29:
|
||||
Improved compliance of the XML Descriptions
|
||||
pretty print for testupnpdescgen
|
||||
|
||||
2006/09/25:
|
||||
improved the Error 404 response.
|
||||
Better serviceType and serviceId for dummy service...
|
||||
|
||||
2006/09/24:
|
||||
updating the XML description generator
|
||||
|
||||
2006/09/18:
|
||||
Thanks to Rick Richard, support for SSDP "alive" and "byebye" notifications
|
||||
was added. The -u options was also added. The SSDP response are now
|
||||
improved.
|
||||
The -o option is now working (to force a specific external IP address).
|
||||
The Soap Methods errors are correctly responded (401 Invalid Action)
|
||||
|
||||
2006/09/09:
|
||||
Added code to handle filter rules. Thanks to Seth Mos (pfsense.com)
|
||||
storing the descriptions in the label of the rule
|
||||
|
||||
2006/09/02:
|
||||
improved the generation of the XML descriptions.
|
||||
I still need to add allowed values to variables.
|
||||
|
||||
2006/07/29:
|
||||
filtering SSDP requests and responding with same ST: field
|
||||
|
||||
2006/07/25:
|
||||
Added a dummy description for the WANDevice
|
||||
|
||||
2006/07/20:
|
||||
Command line arguments processing
|
||||
Added possibility to listen internally on several interfaces
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
MiniUPnP project.
|
||||
(c) 2006-2011 Thomas Bernard
|
||||
Homepage : http://miniupnp.free.fr/
|
||||
Mirror: http://miniupnp.tuxfamily.org/
|
||||
|
||||
miniupnpd is still under active developpement. This documentation is
|
||||
likely to be a little outdated when you read it. So please go on the
|
||||
web forum http://miniupnp.tuxfamily.org/ if you need more information.
|
||||
|
||||
================================ *BSD/pf =================================
|
||||
To Build and Install :
|
||||
|
||||
- use BSD make to compile.
|
||||
- you can first 'make config.h' then edit config.h to your preferences and
|
||||
finally 'make'
|
||||
- add "rdr-anchor miniupnpd" and "anchor miniupnpd" lines to /etc/pf.conf
|
||||
- some FreeBSD users reported that it is also necessary for them
|
||||
to explicitly allow udp traffic on 239.0.0.0/8 by adding the two following
|
||||
lines to /etc/pf.conf :
|
||||
pass out on $int_if from any to 239.0.0.0/8 keep state
|
||||
pass in on $int_if from any to 239.0.0.0/8 keep state
|
||||
- dont forget to " pfctl -f /etc/pf.conf "
|
||||
- you can check your modifications are taken into accout with
|
||||
"pfctl -s nat" and "pfctl -s rule". Look for the "rdr-anchor miniupnpd"
|
||||
and "anchor miniupnpd" lines.
|
||||
- install as root using :
|
||||
# make install
|
||||
or
|
||||
# PREFIX=/usr/local make install
|
||||
- run as root : The daemon needs rights to modify pf rules.
|
||||
|
||||
edit the /etc/miniupnpd.conf file to set options. All options are also
|
||||
available through command line switches.
|
||||
To stop the daemon use :
|
||||
> kill `cat /var/run/miniupnpd.pid`
|
||||
|
||||
=========================== *BSD,*Solaris/ipf =============================
|
||||
|
||||
genconfig.sh and the Makefile try to detect wether ipf or pf should be
|
||||
used. If it fails, edit config.h and Makefile by hand.
|
||||
In Makefile, the FWNAME variable value should be pf or ipf.
|
||||
Installation steps are allmost the same as with pf.
|
||||
|
||||
*Solaris users would be interested in reading informations from :
|
||||
http://blogs.sun.com/avalon/category/IPFilter
|
||||
|
||||
============================= Mac OS X/ipfw ===============================
|
||||
|
||||
- use 'bsdmake' or 'make -f Makefile.macosx' to build
|
||||
|
||||
|
||||
============================ Linux/netfilter ==============================
|
||||
To Build and install :
|
||||
|
||||
- make sure you have libiptc available on your system :
|
||||
if you are using debian, "apt-get install iptables-dev"
|
||||
Some versions of the iptables-dev package don't include the
|
||||
necessary files : read "how to get libiptc with its headers on debian" below.
|
||||
In anycase, libiptc is available in iptables sources packages
|
||||
from http://netfilter.org
|
||||
- edit and run netfilter/iptables_init.sh shell script.
|
||||
This script must allways be run before the daemon
|
||||
to set up intial rules and chains.
|
||||
- Build and edit the config.h file
|
||||
> make -f Makefile.linux config.h
|
||||
> vi config.h
|
||||
- Build the daemon
|
||||
> make -f Makefile.linux
|
||||
If not using iptables from your system,
|
||||
> IPTABLESPATH=/path/to/iptables-1.4.1 make -f Makefile.linux
|
||||
note : make sure you have iptables with static libraries compiled.
|
||||
use "./configure --enable-static" before compiling iptables
|
||||
- install as root using :
|
||||
> make -f Makefile.linux install
|
||||
- A miniupnpd script should be installed to /etc/init.d
|
||||
and the configuration files to /etc/miniupnpd
|
||||
- anytime, you can use the netfilter/iptables_flush.sh
|
||||
script to flush all rules added by the daemon.
|
||||
- after killing the daemon, you can get back to
|
||||
iptables initial state by runing the netfilter/iptables_removeall.sh
|
||||
script. Don't forget to edit the script to your convinience.
|
||||
|
||||
NOTE: a /etc/init.d/miniupnpd script will be installed.
|
||||
If it suits you, you can use is with start, stop or restart argument.
|
||||
# /etc/init.d/miniupnpd restart
|
||||
|
||||
|
||||
How to get libiptc with its headers on debian :
|
||||
- Use apt-get to get sources :
|
||||
> apt-get source iptables
|
||||
you should then have an iptables-x.x.x/ directory.
|
||||
- configure and compile :
|
||||
> cd iptables-x.x.x/
|
||||
> ./configure --enable-static
|
||||
> make
|
||||
- it is now possible to compile miniupnpd using the following command :
|
||||
> IPTABLESPATH=§path/to/iptables-x.x.x make -f Makefile.linux
|
||||
|
||||
=========================== Configuration =============================
|
||||
Edit the /etc/miniupnpd.conf file to set options. All options are also
|
||||
available through command line switches.
|
||||
|
||||
Miniupnpd supports some kind of security check for allowing or disallowing
|
||||
redirection to be made. The UPnP permission rules are read from the
|
||||
miniupnpd.conf configuration file.
|
||||
When a new redirection is asked, permission rules are evaluated in top-down
|
||||
order and the first permission rule matched gives the answer : redirection
|
||||
allowed or denied. If no rule is matching, the redirection is allowed, so
|
||||
it is a good practice to have a "catch all" deny permission rule at the end
|
||||
of your mermission ruleset.
|
||||
Sample permission ruleset :
|
||||
allow 4662-4672 192.168.1.34/32 4662-4672
|
||||
deny 0-65535 192.168.1.34/32 0-65535
|
||||
allow 1024-65535 192.168.1.0/24 1024-65535
|
||||
deny 0-65535 0.0.0.0/0 0-65535
|
||||
With this ruleset, redirections are allowed only for host on the subnet
|
||||
192.168.1.0/255.255.255.0 for the ports 1024 or above. There is an exception
|
||||
for the host 192.168.1.34 for which only redirections from/to port 4662 to
|
||||
4672 are allowed.
|
||||
|
||||
You can generate the uuid for your UPnP device with the uuidgen available
|
||||
under linux. The following following OpenBSD package is also providing
|
||||
a "uuid" tool :
|
||||
http://www.openbsd.org/4.0_packages/i386/uuid-1.5.0.tgz-long.html
|
||||
An web based uuid generator is also available :
|
||||
http://kruithof.xs4all.nl/uuid/uuidgen
|
||||
|
||||
On linux systems, one could also use the command
|
||||
'cat /proc/sys/kernel/random/uuid' to generate an uuid.
|
||||
|
||||
More simple, use the genuuid makefile target :
|
||||
> make genuuid
|
||||
or
|
||||
> make -f Makefile.linux genuuid
|
||||
This target is needed by the "install" target, so it should be done
|
||||
automatically.
|
||||
|
||||
To stop the daemon use :
|
||||
# kill `cat /var/run/miniupnpd.pid`
|
||||
or if your linux system use /etc/init.d/
|
||||
# /etc/init.d/miniupnpd stop
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
MiniUPnPd
|
||||
Copyright (c) 2006-2011, 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.
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
# $Id: Makefile,v 1.59 2011/05/26 22:47:32 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
# Author: Thomas Bernard
|
||||
#
|
||||
# Makefile for miniupnpd (MiniUPnP daemon)
|
||||
#
|
||||
# This Makefile should work for *BSD and SunOS/Solaris.
|
||||
# On Mac OS X, use "bsdmake" to build.
|
||||
# This Makefile is NOT compatible with GNU Make.
|
||||
# Linux users, please use Makefile.linux :
|
||||
# make -f Makefile.linux
|
||||
|
||||
CFLAGS = -pipe -Wall -Os
|
||||
#CFLAGS = -pipe -Wall -O -g -DDEBUG
|
||||
CC ?= gcc
|
||||
RM = rm -f
|
||||
MV = mv
|
||||
INSTALL = install
|
||||
STRIP = strip
|
||||
|
||||
# OSNAME and FWNAME are used for building OS or FW dependent code.
|
||||
OSNAME != uname -s
|
||||
ARCH != uname -m
|
||||
.ifndef FWNAME
|
||||
.if exists(/usr/include/net/pfvar.h)
|
||||
FWNAME = pf
|
||||
.else
|
||||
FWNAME = ipf
|
||||
.endif
|
||||
.endif
|
||||
|
||||
# better way to find if we are using ipf or pf
|
||||
.if $(OSNAME) == "FreeBSD"
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if checkyesno ipfilter_enable; then \
|
||||
echo "ipf"; else echo "pf"; fi
|
||||
.endif
|
||||
|
||||
.if $(OSNAME) == "NetBSD"
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if checkyesno ipfilter; then \
|
||||
echo "ipf"; else echo "pf"; fi
|
||||
.endif
|
||||
|
||||
.if $(OSNAME) == "DragonFly"
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if chechyesno ipfilter; then \
|
||||
echo "ipf"; else echo "pf"; fi
|
||||
.endif
|
||||
|
||||
.if $(OSNAME) == "Darwin"
|
||||
FWNAME = ipfw
|
||||
.endif
|
||||
|
||||
# Solaris specific CFLAGS
|
||||
.if $(OSNAME) == "SunOS"
|
||||
CFLAGS += -DSOLARIS2=`uname -r | cut -d. -f2`
|
||||
.if $(ARCH) == "amd64"
|
||||
CFLAGS += -m64 -mcmodel=kernel -mno-red-zone -ffreestanding
|
||||
.elif $(ARCH) == "sparc64"
|
||||
CFLAGS += -m64 -mcmodel=medlow
|
||||
.endif
|
||||
.endif
|
||||
|
||||
STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o \
|
||||
upnpevents.o upnputils.o getconnstatus.o
|
||||
BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o
|
||||
SUNOSOBJS = solaris/getifstats.o bsd/ifacewatcher.o
|
||||
MACOBJS = mac/getifstats.o bsd/ifacewatcher.o
|
||||
PFOBJS = pf/obsdrdr.o
|
||||
IPFOBJS = ipf/ipfrdr.o
|
||||
IPFWOBJS = ipfw/ipfwrdr.o
|
||||
MISCOBJS = upnpreplyparse.o minixml.o
|
||||
|
||||
ALLOBJS = $(STDOBJS) $(MISCOBJS)
|
||||
.if $(OSNAME) == "SunOS"
|
||||
ALLOBJS += $(SUNOSOBJS)
|
||||
TESTGETIFSTATSOBJS = testgetifstats.o solaris/getifstats.o
|
||||
.elif $(OSNAME) == "Darwin"
|
||||
ALLOBJS += $(MACOBJS)
|
||||
TESTGETIFSTATSOBJS = testgetifstats.o mac/getifstats.o
|
||||
.else
|
||||
ALLOBJS += $(BSDOBJS)
|
||||
TESTGETIFSTATSOBJS = testgetifstats.o bsd/getifstats.o
|
||||
.endif
|
||||
|
||||
.if $(FWNAME) == "pf"
|
||||
ALLOBJS += $(PFOBJS)
|
||||
.elif $(FWNAME) == "ipfw"
|
||||
ALLOBJS += $(IPFWOBJS)
|
||||
.else
|
||||
ALLOBJS += $(IPFOBJS)
|
||||
.endif
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o
|
||||
TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o
|
||||
MINIUPNPDCTLOBJS = miniupnpdctl.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
testupnppermissions miniupnpdctl \
|
||||
testgetifaddr
|
||||
.if $(OSNAME) == "Darwin"
|
||||
LIBS =
|
||||
.else
|
||||
LIBS = -lkvm
|
||||
.endif
|
||||
.if $(OSNAME) == "SunOS"
|
||||
LIBS += -lsocket -lnsl -lkstat -lresolv
|
||||
.endif
|
||||
|
||||
# set PREFIX variable to install in the wanted place
|
||||
|
||||
INSTALLBINDIR = $(PREFIX)/sbin
|
||||
INSTALLETCDIR = $(PREFIX)/etc
|
||||
# INSTALLMANDIR = $(PREFIX)/man
|
||||
INSTALLMANDIR = /usr/share/man
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
$(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \
|
||||
testupnpdescgen.o \
|
||||
$(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \
|
||||
miniupnpdctl.o testgetifaddr.o \
|
||||
$(PFOBJS) $(IPFOBJS) $(IPFWOBJS)
|
||||
|
||||
install: miniupnpd genuuid
|
||||
$(STRIP) miniupnpd
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR)
|
||||
$(INSTALL) -m 555 miniupnpd $(DESTDIR)$(INSTALLBINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR)
|
||||
$(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR)
|
||||
# TODO : install man page correctly
|
||||
# $(INSTALL) -d $(INSTALLMANDIR)
|
||||
# $(INSTALL) miniupnpd.1 $(INSTALLMANDIR)/cat1/miniupnpd.0
|
||||
|
||||
# genuuid is using the uuid cli tool available under OpenBSD 4.0 in
|
||||
# the uuid-1.5.0 package
|
||||
# any other cli tool returning a uuid on stdout should work.
|
||||
UUID != if which uuidgen 2>&1 > /dev/null; then \
|
||||
echo `uuidgen` ; \
|
||||
elif which uuid 2>&1 > /dev/null; then \
|
||||
echo `uuid` ; \
|
||||
else echo "00000000-0000-0000-0000-000000000000"; \
|
||||
fi
|
||||
|
||||
genuuid:
|
||||
$(MV) miniupnpd.conf miniupnpd.conf.before
|
||||
sed -e "s/^uuid=[-0-9a-fA-F]*/uuid=$(UUID)/" miniupnpd.conf.before > miniupnpd.conf
|
||||
$(RM) miniupnpd.conf.before
|
||||
|
||||
depend: config.h
|
||||
mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \
|
||||
testupnppermissions.c miniupnpdctl.c testgetifaddr.c
|
||||
|
||||
miniupnpd: config.h $(ALLOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(ALLOBJS) $(LIBS)
|
||||
|
||||
# BSDmake :
|
||||
# $(CC) $(CFLAGS) -o $@ $> $(LIBS)
|
||||
|
||||
miniupnpdctl: config.h $(MINIUPNPDCTLOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(MINIUPNPDCTLOBJS)
|
||||
|
||||
testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTUPNPDESCGENOBJS)
|
||||
|
||||
testgetifstats: config.h $(TESTGETIFSTATSOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS)
|
||||
|
||||
testgetifaddr: config.h $(TESTGETIFADDROBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTGETIFADDROBJS)
|
||||
|
||||
testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS)
|
||||
|
||||
# gmake :
|
||||
# $(CC) $(CFLAGS) -o $@ $^
|
||||
# BSDmake :
|
||||
# $(CC) $(CFLAGS) -o $@ $>
|
||||
|
||||
config.h: genconfig.sh
|
||||
./genconfig.sh
|
||||
|
||||
.SUFFIXES: .o .c
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
# $(CC) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC)
|
||||
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
# $Id: Makefile.linux,v 1.60 2011/07/30 13:14:35 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# (c) 2006-2011 Thomas Bernard
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
# Author : Thomas Bernard
|
||||
# for use with GNU Make
|
||||
#
|
||||
# To install use :
|
||||
# $ PREFIX=/dummyinstalldir make -f Makefile.linux install
|
||||
# or :
|
||||
# $ INSTALLPREFIX=/usr/local make -f Makefile.linux install
|
||||
# or :
|
||||
# $ make -f Makefile.linux install
|
||||
#
|
||||
# if your system hasn't iptables libiptc headers and binary correctly
|
||||
# installed, you need to get iptables sources from http://netfilter.org/
|
||||
# ./configure them and build them then miniupnpd will build using :
|
||||
# $ IPTABLESPATH=/path/to/iptables-1.4.1 make -f Makefile.linux
|
||||
#
|
||||
#CFLAGS = -Wall -O -D_GNU_SOURCE -g -DDEBUG
|
||||
CFLAGS ?= -Wall -Os -D_GNU_SOURCE -fno-strict-aliasing -Wstrict-prototypes
|
||||
CC ?= gcc
|
||||
RM = rm -f
|
||||
INSTALL = install
|
||||
STRIP ?= strip
|
||||
CP = cp
|
||||
|
||||
|
||||
INSTALLPREFIX ?= $(PREFIX)/usr
|
||||
SBININSTALLDIR = $(INSTALLPREFIX)/sbin
|
||||
ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd
|
||||
|
||||
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||
upnpreplyparse.o minixml.o \
|
||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o \
|
||||
upnpevents.o upnputils.o getconnstatus.o
|
||||
|
||||
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o
|
||||
NETFILTEROBJS = netfilter/iptcrdr.o
|
||||
|
||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||
|
||||
ifeq "$(wildcard /etc/gentoo-release )" ""
|
||||
LIBS ?= -liptc
|
||||
else # gentoo
|
||||
# the following is better, at least on gentoo with iptables 1.4.6
|
||||
# see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1618
|
||||
# and http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183
|
||||
LIBS ?= -lip4tc
|
||||
endif
|
||||
|
||||
ARCH ?= $(shell uname -m | grep -q "x86_64" && echo 64)
|
||||
ifdef IPTABLESPATH
|
||||
CFLAGS := $(CFLAGS) -I$(IPTABLESPATH)/include/
|
||||
LDFLAGS := $(LDFLAFGS) -L$(IPTABLESPATH)/libiptc/
|
||||
# get iptables version and set IPTABLES_143 macro if needed
|
||||
ifeq ($(TARGET_OPENWRT),)
|
||||
IPTABLESVERSION := $(shell grep "\#define VERSION" $(IPTABLESPATH)/config.h | tr -d \" |cut -d" " -f3 )
|
||||
IPTABLESVERSION1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 )
|
||||
IPTABLESVERSION2 := $(shell echo $(IPTABLESVERSION) | cut -d. -f2 )
|
||||
IPTABLESVERSION3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 )
|
||||
# test if iptables version >= 1.4.3
|
||||
TEST := $(shell [ \( \( $(IPTABLESVERSION1) -ge 1 \) -a \( $(IPTABLESVERSION2) -ge 4 \) \) -a \( $(IPTABLESVERSION3) -ge 3 \) ] && echo 1 )
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
# the following sucks, but works
|
||||
LIBS = $(IPTABLESPATH)/libiptc/.libs/libip4tc.o
|
||||
#LIBS = $(IPTABLESPATH)/libiptc/.libs/libiptc.a
|
||||
else # ifeq ($(TEST), 1)
|
||||
LIBS = $(IPTABLESPATH)/libiptc/libiptc.a
|
||||
endif # ifeq ($(TEST), 1)
|
||||
else # ($(TARGET_OPENWRT),)
|
||||
# openWRT :
|
||||
# check for system-wide iptables files. Test if iptables version >= 1.4.3
|
||||
# the following test has to be verified :
|
||||
TEST := $(shell test -f /usr/include/iptables/internal.h && grep -q "\#define IPTABLES_VERSION" /usr/include/iptables/internal.h && echo 1)
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
LIBS = -liptc
|
||||
endif # ($(TEST), 1)
|
||||
TEST_LIB := $(shell test -f /usr/lib$(ARCH)/libiptc.a && echo 1)
|
||||
ifeq ($(TEST_LIB), 1)
|
||||
LIBS = -liptc /usr/lib$(ARCH)/libiptc.a
|
||||
endif # ($(TEST_LIB), 1)
|
||||
endif # ($(TARGET_OPENWRT),)
|
||||
else # ifdef IPTABLESPATH
|
||||
# IPTABLESPATH not defined
|
||||
# the following test has to be verified :
|
||||
TEST := $(shell test -f /usr/include/xtables.h && grep -q "XTABLES_VERSION_CODE" /usr/include/xtables.h && echo 1)
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
LIBS = -lip4tc
|
||||
endif # ($(TEST), 1)
|
||||
endif # ifdef IPTABLESPATH
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
testupnppermissions miniupnpdctl testgetifaddr
|
||||
|
||||
.PHONY: all clean install depend genuuid
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALLOBJS)
|
||||
$(RM) $(EXECUTABLES)
|
||||
$(RM) testupnpdescgen.o testgetifstats.o
|
||||
$(RM) testupnppermissions.o testgetifaddr.o
|
||||
$(RM) miniupnpdctl.o
|
||||
|
||||
install: miniupnpd genuuid
|
||||
$(STRIP) miniupnpd
|
||||
$(INSTALL) -d $(SBININSTALLDIR)
|
||||
$(INSTALL) miniupnpd $(SBININSTALLDIR)
|
||||
$(INSTALL) -d $(ETCINSTALLDIR)
|
||||
$(INSTALL) netfilter/iptables_init.sh $(ETCINSTALLDIR)
|
||||
$(INSTALL) netfilter/iptables_removeall.sh $(ETCINSTALLDIR)
|
||||
$(INSTALL) --mode=0644 -b miniupnpd.conf $(ETCINSTALLDIR)
|
||||
$(INSTALL) -d $(PREFIX)/etc/init.d
|
||||
$(INSTALL) linux/miniupnpd.init.d.script $(PREFIX)/etc/init.d/miniupnpd
|
||||
|
||||
# genuuid is using the uuidgen CLI tool which is part of libuuid
|
||||
# from the e2fsprogs
|
||||
genuuid:
|
||||
ifeq ($(TARGET_OPENWRT),)
|
||||
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen||uuid) 2>/dev/null`/" miniupnpd.conf
|
||||
else
|
||||
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf
|
||||
endif
|
||||
|
||||
miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) $(LIBS)
|
||||
|
||||
testupnpdescgen: $(TESTUPNPDESCGENOBJS)
|
||||
|
||||
testgetifstats: testgetifstats.o linux/getifstats.o
|
||||
|
||||
testupnppermissions: testupnppermissions.o upnppermissions.o
|
||||
|
||||
testgetifaddr: testgetifaddr.o getifaddr.o
|
||||
|
||||
miniupnpdctl: miniupnpdctl.o
|
||||
|
||||
config.h: genconfig.sh
|
||||
./genconfig.sh
|
||||
|
||||
depend: config.h
|
||||
makedepend -f$(MAKEFILE_LIST) -Y \
|
||||
$(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \
|
||||
testgetifstats.c 2>/dev/null
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
miniupnpd.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||
miniupnpd.o: upnphttp.h upnpdescgen.h miniupnpdpath.h getifaddr.h upnpsoap.h
|
||||
miniupnpd.o: options.h minissdp.h upnpredirect.h daemonize.h upnpevents.h
|
||||
miniupnpd.o: natpmp.h commonrdr.h upnputils.h ifacewatcher.h
|
||||
upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h
|
||||
upnphttp.o: upnpevents.h
|
||||
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
|
||||
upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h
|
||||
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
|
||||
upnpsoap.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||
upnpsoap.o: upnphttp.h upnpsoap.h upnpreplyparse.h upnpredirect.h getifaddr.h
|
||||
upnpsoap.o: getifstats.h getconnstatus.h upnpurns.h
|
||||
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||
minixml.o: minixml.h
|
||||
upnpredirect.o: config.h upnpredirect.h upnpglobalvars.h upnppermissions.h
|
||||
upnpredirect.o: miniupnpdtypes.h upnpevents.h netfilter/iptcrdr.h commonrdr.h
|
||||
getifaddr.o: config.h getifaddr.h
|
||||
daemonize.o: daemonize.h config.h
|
||||
upnpglobalvars.o: config.h upnpglobalvars.h upnppermissions.h
|
||||
upnpglobalvars.o: miniupnpdtypes.h
|
||||
options.o: options.h config.h upnppermissions.h upnpglobalvars.h
|
||||
options.o: miniupnpdtypes.h
|
||||
upnppermissions.o: config.h upnppermissions.h
|
||||
minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h
|
||||
minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h
|
||||
minissdp.o: upnputils.h codelength.h
|
||||
natpmp.o: config.h natpmp.h upnpglobalvars.h upnppermissions.h
|
||||
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h
|
||||
upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h
|
||||
upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h
|
||||
upnputils.o: config.h upnputils.h
|
||||
getconnstatus.o: getconnstatus.h getifaddr.h
|
||||
linux/getifstats.o: config.h getifstats.h
|
||||
linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h
|
||||
linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
|
||||
linux/ifacewatcher.o: upnppermissions.h natpmp.h
|
||||
netfilter/iptcrdr.o: netfilter/iptcrdr.h commonrdr.h config.h
|
||||
netfilter/iptcrdr.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||
testupnpdescgen.o: config.h upnpdescgen.h
|
||||
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
|
||||
upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h
|
||||
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
|
||||
testgetifstats.o: getifstats.h
|
|
@ -0,0 +1,116 @@
|
|||
# MiniUPnP project
|
||||
# http://miniupnp.free.fr/
|
||||
# Author: Thomas Bernard
|
||||
# This Makefile should work for MacOSX
|
||||
#
|
||||
# To install use :
|
||||
# $ PREFIX=/dummyinstalldir make -f Makefile.macosx install
|
||||
# or :
|
||||
# $ make -f Makefile.macosx install
|
||||
#
|
||||
CFLAGS = -Wall -O -g3 -DDEBUG
|
||||
#CFLAGS = -Wall -Os
|
||||
CC = gcc
|
||||
RM = rm -f
|
||||
MV = mv
|
||||
INSTALL = install
|
||||
STRIP = strip
|
||||
|
||||
# OSNAME and FWNAME are used for building OS or FW dependent code.
|
||||
OSNAME = $(shell uname)
|
||||
ARCH = $(shell uname -p)
|
||||
FWNAME = ipfw
|
||||
|
||||
STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o \
|
||||
upnpevents.o getconnstatus.o upnputils.o
|
||||
MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o
|
||||
IPFW_OBJS = ipfw/ipfwrdr.o
|
||||
MISC_OBJS = upnpreplyparse.o minixml.o
|
||||
|
||||
ALL_OBJS = $(STD_OBJS) $(MISC_OBJS) $(MAC_OBJS) $(IPFW_OBJS)
|
||||
|
||||
TEST_UPNPDESCGEN_OBJS = testupnpdescgen.o upnpdescgen.o
|
||||
TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o
|
||||
TEST_UPNPPERMISSIONS_OBJS = testupnppermissions.o upnppermissions.o
|
||||
TEST_GETIFADDR_OBJS = testgetifaddr.o getifaddr.o
|
||||
MINIUPNPDCTL_OBJS = miniupnpdctl.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
testupnppermissions miniupnpdctl \
|
||||
testgetifaddr
|
||||
|
||||
LIBS =
|
||||
|
||||
# set PREFIX variable to install in the wanted place
|
||||
|
||||
INSTALL_BINDIR = $(PREFIX)/sbin
|
||||
INSTALL_ETCDIR = $(PREFIX)/etc/miniupnpd
|
||||
# INSTALL_MANDIR = $(PREFIX)/man
|
||||
INSTALL_MANDIR = /usr/share/man/man1
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALL_OBJS) $(EXECUTABLES) \
|
||||
testupnpdescgen.o testgetifstats.o testupnppermissions.o \
|
||||
miniupnpdctl.o testgetifaddr.o config.h
|
||||
|
||||
install: miniupnpd genuuid
|
||||
$(STRIP) miniupnpd
|
||||
$(INSTALL) -d $(INSTALL_BINDIR)
|
||||
$(INSTALL) miniupnpd $(INSTALL_BINDIR)
|
||||
$(INSTALL) -d $(INSTALL_ETCDIR)
|
||||
$(INSTALL) ipfw/ipfw_init.sh $(INSTALL_ETCDIR)
|
||||
$(INSTALL) ipfw/ipfw_removeall.sh $(INSTALL_ETCDIR)
|
||||
$(INSTALL) --mode=0644 -b miniupnpd.conf $(INSTALL_ETCDIR)
|
||||
$(INSTALL) -d $(INSTALL_MANDIR)
|
||||
$(INSTALL) miniupnpd.1 $(INSTALL_MANDIR)
|
||||
# TODO Fix these paths and those within the plist
|
||||
$(INSTALL) -d $(PREFIX)/Library/LaunchDaemons
|
||||
$(INSTALL) mac/org.tuxfamily.miniupnpd.plist $(PREFIX)/Library/LaunchDaemons
|
||||
|
||||
# genuuid is using the uuid cli tool available under MacOSX
|
||||
UUID != if which uuidgen 2>&1 > /dev/null; then \
|
||||
echo `uuidgen` ; \
|
||||
elif which uuid 2>&1 > /dev/null; then \
|
||||
echo `uuid` ; \
|
||||
else echo "00000000-0000-0000-0000-000000000000"; \
|
||||
fi
|
||||
|
||||
genuuid:
|
||||
$(MV) miniupnpd.conf miniupnpd.conf.before
|
||||
sed -e "s/^uuid=[-0-9a-f]*/uuid=$(UUID)/" miniupnpd.conf.before > miniupnpd.conf
|
||||
$(RM) miniupnpd.conf.before
|
||||
|
||||
depend: config.h
|
||||
mkdep $(ALL_OBJS:.o=.c) testupnpdescgen.c testgetifstats.c \
|
||||
testupnppermissions.c miniupnpdctl.c testgetifaddr.c
|
||||
|
||||
miniupnpd: config.h $(ALL_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(ALL_OBJS) $(LIBS)
|
||||
|
||||
miniupnpdctl: config.h $(MINIUPNPDCTL_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(MINIUPNPDCTL_OBJS)
|
||||
|
||||
testupnpdescgen: config.h $(TEST_UPNPDESCGEN_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_UPNPDESCGEN_OBJS)
|
||||
|
||||
testgetifstats: config.h $(TEST_GETIFSTATS_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_GETIFSTATS_OBJS) $(LIBS)
|
||||
|
||||
testgetifaddr: config.h $(TEST_GETIFADDR_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_GETIFADDR_OBJS)
|
||||
|
||||
testupnppermissions: config.h $(TEST_UPNPPERMISSIONS_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TEST_UPNPPERMISSIONS_OBJS)
|
||||
|
||||
|
||||
config.h: genconfig.sh
|
||||
./genconfig.sh
|
||||
|
||||
.SUFFIXES: .o .c
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
# $(CC) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC)
|
|
@ -0,0 +1,30 @@
|
|||
MiniUPnP project
|
||||
(c) 2006-2011 Thomas Bernard
|
||||
webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
contact: miniupnp@free.fr
|
||||
|
||||
This directory contain the miniUPnP daemon software.
|
||||
This software is subject to the conditions detailed in
|
||||
the LICENCE file provided with this distribution.
|
||||
|
||||
|
||||
The miniUPnP daemon is an UPnP IGD (internet gateway device)
|
||||
which provide NAT traversal services to any UPnP enabled client on
|
||||
the network.
|
||||
See http://www.upnp.org/ for more details on UPnP.
|
||||
During the year 2011, support for IGD v2 has been added.
|
||||
This support is experimental, and should be enabled only
|
||||
for testing and development.
|
||||
|
||||
Later, support for the NAT Port Mapping Protocol (NAT-PMP) was
|
||||
added. See information about NAT-PMP here :
|
||||
http://miniupnp.free.fr/nat-pmp.html
|
||||
|
||||
Read the INSTALL files for instructions to compile, install and
|
||||
configure miniupnpd.
|
||||
|
||||
Report bugs to miniupnp@free.fr or on the web forum :
|
||||
http://miniupnp.tuxfamily.org/forum/
|
||||
|
||||
Thomas Bernard
|
||||
|
|
@ -0,0 +1 @@
|
|||
1.6
|
|
@ -0,0 +1,20 @@
|
|||
# $Id: Makefile,v 1.2 2011/05/20 09:34:25 nanard Exp $
|
||||
# made for GNU Make
|
||||
CFLAGS = -Wall -g
|
||||
EXECUTABLES = testgetifstats testifacewatcher
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXECUTABLES)
|
||||
|
||||
testobsdrdr.o: testobsdrdr.c obsdrdr.h
|
||||
|
||||
testgetifstats: testgetifstats.o getifstats.o
|
||||
$(CC) $(CFLAGS) -o $@ $> -lkvm
|
||||
|
||||
testifacewatcher: testifacewatcher.o ifacewatcher.o upnputils.o
|
||||
$(CC) $(CFLAGS) -o $@ $>
|
||||
|
||||
upnputils.o: ../upnputils.c
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner and Thomas Bernard
|
||||
* (c) 2006 Ryan Wagoner
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <net/if_var.h>
|
||||
#endif
|
||||
#if defined(__DragonFly__)
|
||||
#include <net/pf/pfvar.h>
|
||||
#else
|
||||
#include <net/pfvar.h>
|
||||
#endif
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../getifstats.h"
|
||||
#include "../config.h"
|
||||
|
||||
struct nlist list[] = {
|
||||
{"_ifnet"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
int
|
||||
getifstats(const char * ifname, struct ifdata * data)
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
struct ifnethead ifh;
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
struct ifnet_head ifh;
|
||||
#else
|
||||
#error "Dont know if I should use struct ifnethead or struct ifnet_head"
|
||||
#endif
|
||||
struct ifnet ifc;
|
||||
struct ifnet *ifp;
|
||||
kvm_t *kd;
|
||||
ssize_t n;
|
||||
char errstr[_POSIX2_LINE_MAX];
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
static time_t cache_timestamp = 0;
|
||||
static struct ifdata cache_data;
|
||||
time_t current_time;
|
||||
#endif
|
||||
if(!data)
|
||||
return -1;
|
||||
data->baudrate = 4200000;
|
||||
data->opackets = 0;
|
||||
data->ipackets = 0;
|
||||
data->obytes = 0;
|
||||
data->ibytes = 0;
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
current_time = time(NULL);
|
||||
if(current_time == ((time_t)-1)) {
|
||||
syslog(LOG_ERR, "getifstats() : time() error : %m");
|
||||
} else {
|
||||
if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
|
||||
memcpy(data, &cache_data, sizeof(struct ifdata));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);*/
|
||||
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr);
|
||||
if(!kd)
|
||||
{
|
||||
syslog (LOG_ERR, "getifstats() : kvm_open(): %s", errstr);
|
||||
return -1;
|
||||
}
|
||||
if(kvm_nlist(kd, list) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_nlist(): FAILED");
|
||||
goto error;
|
||||
}
|
||||
if(!list[0].n_value)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : n_value(): FAILED");
|
||||
goto error;
|
||||
}
|
||||
n = kvm_read(kd, list[0].n_value, &ifh, sizeof(ifh));
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_read(head): %s", kvm_geterr(kd));
|
||||
goto error;
|
||||
}
|
||||
for(ifp = TAILQ_FIRST(&ifh); ifp; ifp = TAILQ_NEXT(&ifc, if_list))
|
||||
{
|
||||
n = kvm_read(kd, (u_long)ifp, &ifc, sizeof(ifc));
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_read(element): %s", kvm_geterr(kd));
|
||||
goto error;
|
||||
}
|
||||
if(strcmp(ifname, ifc.if_xname) == 0)
|
||||
{
|
||||
/* found the right interface */
|
||||
data->opackets = ifc.if_data.ifi_opackets;
|
||||
data->ipackets = ifc.if_data.ifi_ipackets;
|
||||
data->obytes = ifc.if_data.ifi_obytes;
|
||||
data->ibytes = ifc.if_data.ifi_ibytes;
|
||||
data->baudrate = ifc.if_data.ifi_baudrate;
|
||||
kvm_close(kd);
|
||||
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
if(current_time!=((time_t)-1)) {
|
||||
cache_timestamp = current_time;
|
||||
memcpy(&cache_data, data, sizeof(struct ifdata));
|
||||
}
|
||||
#endif
|
||||
return 0; /* ok */
|
||||
}
|
||||
}
|
||||
error:
|
||||
kvm_close(kd);
|
||||
return -1; /* not found or error */
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/* $Id: ifacewatcher.c,v 1.3 2011/06/04 16:19:51 nanard Exp $ */
|
||||
/* Project MiniUPnP
|
||||
* web : 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 */
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#if !defined(SA_LEN)
|
||||
#define SA_LEN(sa) (sa)->sa_len
|
||||
#endif
|
||||
|
||||
#define SALIGN (sizeof(long) - 1)
|
||||
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
|
||||
|
||||
#include "../upnputils.h"
|
||||
#include "../upnpglobalvars.h"
|
||||
|
||||
extern volatile int should_send_public_address_change_notif;
|
||||
|
||||
int
|
||||
OpenAndConfInterfaceWatchSocket(void)
|
||||
{
|
||||
int s;
|
||||
|
||||
/*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. */
|
||||
if(s < 0) {
|
||||
syslog(LOG_ERR, "OpenAndConfInterfaceWatchSocket socket: %m");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessInterfaceWatchNotify(int s)
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t len;
|
||||
char tmp[64];
|
||||
struct rt_msghdr * rtm;
|
||||
struct if_msghdr * ifm;
|
||||
struct ifa_msghdr * ifam;
|
||||
#ifdef RTM_IFANNOUNCE
|
||||
struct if_announcemsghdr * ifanm;
|
||||
#endif
|
||||
char * p;
|
||||
struct sockaddr * sa;
|
||||
unsigned int ext_if_name_index = 0;
|
||||
|
||||
len = recv(s, buf, sizeof(buf), 0);
|
||||
if(len < 0) {
|
||||
syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
|
||||
return;
|
||||
}
|
||||
if(ext_if_name) {
|
||||
ext_if_name_index = if_nametoindex(ext_if_name);
|
||||
}
|
||||
rtm = (struct rt_msghdr *)buf;
|
||||
syslog(LOG_DEBUG, "%u rt_msg : msglen=%d version=%d type=%d", (unsigned)len,
|
||||
rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type);
|
||||
switch(rtm->rtm_type) {
|
||||
case RTM_IFINFO: /* iface going up/down etc. */
|
||||
ifm = (struct if_msghdr *)buf;
|
||||
syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu",
|
||||
ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index);
|
||||
break;
|
||||
#ifdef RTM_IFANNOUNCE
|
||||
case RTM_IFANNOUNCE: /* iface arrival/departure */
|
||||
ifanm = (struct if_announcemsghdr *)buf;
|
||||
syslog(LOG_DEBUG, " RTM_IFANNOUNCE: index=%hu what=%hu ifname=%s",
|
||||
ifanm->ifan_index, ifanm->ifan_what, ifanm->ifan_name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RTM_IEEE80211
|
||||
case RTM_IEEE80211: /* IEEE80211 wireless event */
|
||||
syslog(LOG_DEBUG, " RTM_IEEE80211");
|
||||
break;
|
||||
#endif
|
||||
case RTM_NEWADDR: /* address being added to iface */
|
||||
ifam = (struct ifa_msghdr *)buf;
|
||||
syslog(LOG_DEBUG, " RTM_NEWADDR: addrs=%x flags=%x index=%hu",
|
||||
ifam->ifam_addrs, ifam->ifam_flags, ifam->ifam_index);
|
||||
p = buf + sizeof(struct ifa_msghdr);
|
||||
while(p < buf + len) {
|
||||
sa = (struct sockaddr *)p;
|
||||
sockaddr_to_string(sa, tmp, sizeof(tmp));
|
||||
syslog(LOG_DEBUG, " %s", tmp);
|
||||
p += SA_RLEN(sa);
|
||||
}
|
||||
if(ifam->ifam_index == ext_if_name_index) {
|
||||
should_send_public_address_change_notif = 1;
|
||||
}
|
||||
break;
|
||||
case RTM_DELADDR: /* address being removed from iface */
|
||||
ifam = (struct ifa_msghdr *)buf;
|
||||
if(ifam->ifam_index == ext_if_name_index) {
|
||||
should_send_public_address_change_notif = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_DEBUG, "unprocessed RTM message type=%d", rtm->rtm_type);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* 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 <stdio.h>
|
||||
|
||||
#include "../getifstats.h"
|
||||
|
||||
int
|
||||
main(int argc, char * * argv)
|
||||
{
|
||||
int r;
|
||||
struct ifdata data;
|
||||
printf("usage: %s if_name\n", argv[0]);
|
||||
if(argc<2)
|
||||
return -1;
|
||||
r = getifstats(argv[1], &data);
|
||||
if(r<0)
|
||||
printf("getifstats() failed\n");
|
||||
else
|
||||
{
|
||||
printf("ipackets = %10lu opackets = %10lu\n",
|
||||
data.ipackets, data.opackets);
|
||||
printf("ibytes = %10lu obytes = %10lu\n",
|
||||
data.ibytes, data.obytes);
|
||||
printf("baudrate = %10lu\n", data.baudrate);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* $Id: testifacewatcher.c,v 1.1 2011/05/20 09:34:25 nanard Exp $ */
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
int
|
||||
OpenAndConfInterfaceWatchSocket(void);
|
||||
|
||||
void
|
||||
ProcessInterfaceWatchNotify(int s);
|
||||
|
||||
const char * ext_if_name;
|
||||
volatile int should_send_public_address_change_notif = 0;
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int s;
|
||||
|
||||
ext_if_name = "ep0";
|
||||
openlog("testifacewatcher", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||
|
||||
syslog(LOG_DEBUG, "test");
|
||||
s = OpenAndConfInterfaceWatchSocket();
|
||||
for(;;) {
|
||||
if(should_send_public_address_change_notif) {
|
||||
syslog(LOG_DEBUG, "should_send_public_address_change_notif !");
|
||||
should_send_public_address_change_notif = 0;
|
||||
}
|
||||
ProcessInterfaceWatchNotify(s);
|
||||
}
|
||||
closelog();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,531 @@
|
|||
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
||||
#else
|
||||
#define _Q_INVALIDATE(a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#ifdef SLIST_ENTRY
|
||||
#undef SLIST_ENTRY
|
||||
#endif
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_END(head) NULL
|
||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != SLIST_END(head); \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
\
|
||||
while (curelm->field.sle_next != (elm)) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
_Q_INVALIDATE((elm)->field.sle_next); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List access methods
|
||||
*/
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_END(head) NULL
|
||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for((var) = LIST_FIRST(head); \
|
||||
(var)!= LIST_END(head); \
|
||||
(var) = LIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST(head) = LIST_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = \
|
||||
&(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_END(head) NULL
|
||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define TAILQ_EMPTY(head) \
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -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
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/* $Id: commonrdr.h,v 1.7 2011/06/22 20:34:39 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* (c) 2006-2011 Thomas Bernard
|
||||
* 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 */
|
||||
#ifndef __COMMONRDR_H__
|
||||
#define __COMMONRDR_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* init and shutdown functions */
|
||||
int
|
||||
init_redirect(void);
|
||||
|
||||
void
|
||||
shutdown_redirect(void);
|
||||
|
||||
/* get_redirect_rule() gets internal IP and port from
|
||||
* interface, external port and protocl
|
||||
*/
|
||||
int
|
||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
|
||||
int
|
||||
get_redirect_rule_by_index(int index,
|
||||
char * ifname, unsigned short * eport,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
int * proto, char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
|
||||
/* return an (malloc'ed) array of "external" port for which there is
|
||||
* a port mapping. number is the size of the array */
|
||||
unsigned short *
|
||||
get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||
int proto, unsigned int * number);
|
||||
|
||||
#endif
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
#! /bin/sh
|
||||
# $Id: genconfig.sh,v 1.50 2011/07/25 16:03:46 nanard Exp $
|
||||
# miniupnp daemon
|
||||
# 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
|
||||
|
||||
RM="rm -f"
|
||||
CONFIGFILE="config.h"
|
||||
CONFIGMACRO="__CONFIG_H__"
|
||||
|
||||
# version reported in XML descriptions
|
||||
#UPNP_VERSION=20070827
|
||||
UPNP_VERSION=`date +"%Y%m%d"`
|
||||
# Facility to syslog
|
||||
LOG_MINIUPNPD="LOG_DAEMON"
|
||||
|
||||
# detecting the OS name and version
|
||||
OS_NAME=`uname -s`
|
||||
OS_VERSION=`uname -r`
|
||||
|
||||
# pfSense special case
|
||||
if [ -f /etc/platform ]; then
|
||||
if [ `cat /etc/platform` = "pfSense" ]; then
|
||||
OS_NAME=pfSense
|
||||
OS_VERSION=`cat /etc/version`
|
||||
fi
|
||||
fi
|
||||
|
||||
# OpenWRT special case
|
||||
if [ -f ./os.openwrt ]; then
|
||||
OS_NAME=OpenWRT
|
||||
OS_VERSION=$(cat ./os.openwrt)
|
||||
fi
|
||||
|
||||
${RM} ${CONFIGFILE}
|
||||
|
||||
echo "/* MiniUPnP Project" >> ${CONFIGFILE}
|
||||
echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${CONFIGFILE}
|
||||
echo " * (c) 2006-2011 Thomas Bernard" >> ${CONFIGFILE}
|
||||
echo " * generated by $0 on `date` */" >> ${CONFIGFILE}
|
||||
echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE}
|
||||
echo "#define $CONFIGMACRO" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "#include <inttypes.h>" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "#define MINIUPNPD_VERSION \"`cat VERSION`\"" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "#define UPNP_VERSION \"$UPNP_VERSION\"" >> ${CONFIGFILE}
|
||||
|
||||
# OS Specific stuff
|
||||
case $OS_NAME in
|
||||
OpenBSD)
|
||||
MAJORVER=`echo $OS_VERSION | cut -d. -f1`
|
||||
MINORVER=`echo $OS_VERSION | cut -d. -f2`
|
||||
#echo "OpenBSD majorversion=$MAJORVER minorversion=$MINORVER"
|
||||
# rtableid was introduced in OpenBSD 4.0
|
||||
if [ $MAJORVER -ge 4 ]; then
|
||||
echo "#define PFRULE_HAS_RTABLEID" >> ${CONFIGFILE}
|
||||
fi
|
||||
# from the 3.8 version, packets and bytes counters are double : in/out
|
||||
if [ \( $MAJORVER -ge 4 \) -o \( $MAJORVER -eq 3 -a $MINORVER -ge 8 \) ]; then
|
||||
echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE}
|
||||
fi
|
||||
# from the 4.7 version, new pf
|
||||
if [ \( $MAJORVER -ge 5 \) -o \( $MAJORVER -eq 4 -a $MINORVER -ge 7 \) ]; then
|
||||
echo "#define PF_NEWSTYLE" >> ${CONFIGFILE}
|
||||
fi
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.openbsd.org/
|
||||
;;
|
||||
FreeBSD)
|
||||
VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'`
|
||||
if [ $VER -ge 700049 ]; then
|
||||
echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE}
|
||||
fi
|
||||
# new way to see which one to use PF or IPF.
|
||||
# see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=957
|
||||
# source file with handy subroutines like checkyesno
|
||||
. /etc/rc.subr
|
||||
# source config file so we can probe vars
|
||||
. /etc/rc.conf
|
||||
if checkyesno ipfilter_enable; then
|
||||
echo "Using ipf"
|
||||
FW=ipf
|
||||
echo "#define USE_IPF 1" >> ${CONFIGFILE}
|
||||
elif checkyesno pf_enable; then
|
||||
echo "Using pf"
|
||||
FW=pf
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
# TODO : Add support for IPFW
|
||||
# echo "#define USE_IPFW 1" >> ${CONFIGFILE}
|
||||
# FW=ipfw
|
||||
else
|
||||
echo "Could not detect usage of ipf or pf. Compiling for pf by default"
|
||||
FW=pf
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
fi
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.freebsd.org/
|
||||
;;
|
||||
pfSense)
|
||||
# we need to detect if PFRULE_INOUT_COUNTS macro is needed
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.pfsense.com/
|
||||
;;
|
||||
NetBSD)
|
||||
# source file with handy subroutines like checkyesno
|
||||
. /etc/rc.subr
|
||||
# source config file so we can probe vars
|
||||
. /etc/rc.conf
|
||||
if checkyesno pf; then
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
elif checkyesno ipfilter; then
|
||||
echo "#define USE_IPF 1" >> ${CONFIGFILE}
|
||||
FW=ipf
|
||||
else
|
||||
echo "Could not detect ipf nor pf, defaulting to pf."
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
fi
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.netbsd.org/
|
||||
;;
|
||||
DragonFly)
|
||||
# source file with handy subroutines like checkyesno
|
||||
. /etc/rc.subr
|
||||
# source config file so we can probe vars
|
||||
. /etc/rc.conf
|
||||
if checkyesno pf; then
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
elif checkyesno ipfilter; then
|
||||
echo "#define USE_IPF 1" >> ${CONFIGFILE}
|
||||
FW=ipf
|
||||
else
|
||||
echo "Could not detect ipf nor pf, defaulting to pf."
|
||||
echo "#define USE_PF 1" >> ${CONFIGFILE}
|
||||
FW=pf
|
||||
fi
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.dragonflybsd.org/
|
||||
;;
|
||||
SunOS)
|
||||
echo "#define USE_IPF 1" >> ${CONFIGFILE}
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
FW=ipf
|
||||
echo "#define LOG_PERROR 0" >> ${CONFIGFILE}
|
||||
echo "#define SOLARIS_KSTATS 1" >> ${CONFIGFILE}
|
||||
OS_URL=http://www.sun.com/solaris/
|
||||
;;
|
||||
Linux)
|
||||
OS_URL=http://www.kernel.org/
|
||||
KERNVERA=`echo $OS_VERSION | awk -F. '{print $1}'`
|
||||
KERNVERB=`echo $OS_VERSION | awk -F. '{print $2}'`
|
||||
KERNVERC=`echo $OS_VERSION | awk -F. '{print $3}'`
|
||||
KERNVERD=`echo $OS_VERSION | awk -F. '{print $4}'`
|
||||
#echo "$KERNVERA.$KERNVERB.$KERNVERC.$KERNVERD"
|
||||
# Debian GNU/Linux special case
|
||||
if [ -f /etc/debian_version ]; then
|
||||
OS_NAME=Debian
|
||||
OS_VERSION=`cat /etc/debian_version`
|
||||
OS_URL=http://www.debian.org/
|
||||
fi
|
||||
# same thing for Gentoo linux
|
||||
if [ -f /etc/gentoo-release ]; then
|
||||
OS_NAME=Gentoo
|
||||
OS_VERSION=`cat /etc/gentoo-release`
|
||||
OS_URL=http://www.gentoo.org/
|
||||
fi
|
||||
# use lsb_release (Linux Standard Base) when available
|
||||
LSB_RELEASE=`which lsb_release`
|
||||
if [ 0 -eq $? ]; then
|
||||
OS_NAME=`${LSB_RELEASE} -i -s`
|
||||
OS_VERSION=`${LSB_RELEASE} -r -s`
|
||||
case $OS_NAME in
|
||||
Debian)
|
||||
OS_URL=http://www.debian.org/
|
||||
OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||
;;
|
||||
Ubuntu)
|
||||
OS_URL=http://www.ubuntu.com/
|
||||
OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||
;;
|
||||
Gentoo)
|
||||
OS_URL=http://www.gentoo.org/
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo "#define USE_NETFILTER 1" >> ${CONFIGFILE}
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
FW=netfilter
|
||||
;;
|
||||
OpenWRT)
|
||||
OS_URL=http://www.openwrt.org/
|
||||
echo "#define USE_NETFILTER 1" >> ${CONFIGFILE}
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
FW=netfilter
|
||||
;;
|
||||
Darwin)
|
||||
echo "#define USE_IPFW 1" >> ${CONFIGFILE}
|
||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||
FW=ipfw
|
||||
OS_URL=http://developer.apple.com/macosx
|
||||
;;
|
||||
*)
|
||||
echo "Unknown OS : $OS_NAME"
|
||||
echo "Please contact the author at http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software."
|
||||
echo "Please edit config.h for more compilation options."
|
||||
|
||||
# define SUPPORT_REMOTEHOST if the FW related code really supports setting
|
||||
# a RemoteHost
|
||||
if [ \( "$FW" = "netfilter" \) -o \( "$FW" = "pf" \) -o \( "$FW" = "ipfw" \) ] ; then
|
||||
echo "#define SUPPORT_REMOTEHOST" >> ${CONFIGFILE}
|
||||
fi
|
||||
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "#define OS_NAME \"$OS_NAME\"" >> ${CONFIGFILE}
|
||||
echo "#define OS_VERSION \"$OS_NAME/$OS_VERSION\"" >> ${CONFIGFILE}
|
||||
echo "#define OS_URL \"${OS_URL}\"" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* syslog facility to be used by miniupnpd */" >> ${CONFIGFILE}
|
||||
echo "#define LOG_MINIUPNPD ${LOG_MINIUPNPD}" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to allow miniupnpd to be" >> ${CONFIGFILE}
|
||||
echo " * controlled by miniupnpdctl */" >> ${CONFIGFILE}
|
||||
echo "/*#define USE_MINIUPNPDCTL*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_NATPMP" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to enable generation of" >> ${CONFIGFILE}
|
||||
echo " * filter rules with pf */" >> ${CONFIGFILE}
|
||||
echo "/*#define PF_ENABLE_FILTER_RULES*/">> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to enable caching of results of" >> ${CONFIGFILE}
|
||||
echo " * the getifstats() function */" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_GETIFSTATS_CACHING*/" >> ${CONFIGFILE}
|
||||
echo "/* The cache duration is indicated in seconds */" >> ${CONFIGFILE}
|
||||
echo "#define GETIFSTATS_CACHING_DURATION 2" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to enable multiple external ip support */" >> ${CONFIGFILE}
|
||||
echo "/* note : That is EXPERIMENTAL, do not use that unless you know perfectly what you are doing */" >> ${CONFIGFILE}
|
||||
echo "/* Dynamic external ip adresses are not supported when this option is enabled." >> ${CONFIGFILE}
|
||||
echo " * Also note that you would need to configure your .conf file accordingly. */" >> ${CONFIGFILE}
|
||||
echo "/*#define MULTIPLE_EXTERNAL_IP*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Comment the following line to use home made daemonize() func instead" >> ${CONFIGFILE}
|
||||
echo " * of BSD daemon() */" >> ${CONFIGFILE}
|
||||
echo "#define USE_DAEMON" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to enable lease file support */" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_LEASEFILE*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE}
|
||||
echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE}
|
||||
echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE}
|
||||
echo " * option. */" >> ${CONFIGFILE}
|
||||
echo "/*#define HAS_DUMMY_SERVICE*/" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_L3F_SERVICE" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Enable IP v6 support */" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_IPV6*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE}
|
||||
echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE}
|
||||
echo " * control points, so enable with care. */" >> ${CONFIGFILE}
|
||||
echo "/*#define IGD_V2*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "#ifdef IGD_V2" >> ${CONFIGFILE}
|
||||
echo "/* Enable DeviceProtection service (IGDv2) */" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_DP_SERVICE" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "/* Enable WANIPv6FirewallControl service (IGDv2). needs IPv6 */" >> ${CONFIGFILE}
|
||||
echo "#ifdef ENABLE_IPV6" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_6FC_SERVICE" >> ${CONFIGFILE}
|
||||
echo "#endif /* ENABLE_IPV6 */" >> ${CONFIGFILE}
|
||||
echo "#endif /* IGD_V2 */" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* UPnP Events support. Working well enough to be enabled by default." >> ${CONFIGFILE}
|
||||
echo " * It can be disabled to save a few bytes. */" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_EVENTS" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* include interface name in pf and ipf rules */" >> ${CONFIGFILE}
|
||||
echo "#define USE_IFNAME_IN_RULES" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Experimental NFQUEUE support. */" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_NFQUEUE*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Enable to make MiniUPnPd more strict about UPnP conformance" >> ${CONFIGFILE}
|
||||
echo " * and the messages it receives from control points */" >> ${CONFIGFILE}
|
||||
echo "/*#define UPNP_STRICT*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "#endif" >> ${CONFIGFILE}
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,74 @@
|
|||
/* $Id: getconnstatus.c,v 1.4 2011/05/23 20:22: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 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include "getconnstatus.h"
|
||||
#include "getifaddr.h"
|
||||
|
||||
#define STATUS_UNCONFIGURED (0)
|
||||
#define STATUS_CONNECTING (1)
|
||||
#define STATUS_CONNECTED (2)
|
||||
#define STATUS_PENDINGDISCONNECT (3)
|
||||
#define STATUS_DISCONNECTING (4)
|
||||
#define STATUS_DISCONNECTED (5)
|
||||
|
||||
/**
|
||||
* get the connection status
|
||||
* return values :
|
||||
* 0 - Unconfigured
|
||||
* 1 - Connecting
|
||||
* 2 - Connected
|
||||
* 3 - PendingDisconnect
|
||||
* 4 - Disconnecting
|
||||
* 5 - Disconnected */
|
||||
int
|
||||
get_wan_connection_status(const char * ifname)
|
||||
{
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
int r;
|
||||
|
||||
/* we need a better implementation here.
|
||||
* I'm afraid it should be device specific */
|
||||
r = getifaddr(ifname, addr, INET_ADDRSTRLEN);
|
||||
return (r < 0) ? STATUS_DISCONNECTED : STATUS_CONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the same value as get_wan_connection_status()
|
||||
* as a C string */
|
||||
const char *
|
||||
get_wan_connection_status_str(const char * ifname)
|
||||
{
|
||||
int status;
|
||||
const char * str = NULL;
|
||||
|
||||
status = get_wan_connection_status(ifname);
|
||||
switch(status) {
|
||||
case 0:
|
||||
str = "Unconfigured";
|
||||
break;
|
||||
case 1:
|
||||
str = "Connecting";
|
||||
break;
|
||||
case 2:
|
||||
str = "Connected";
|
||||
break;
|
||||
case 3:
|
||||
str = "PendingDisconnect";
|
||||
break;
|
||||
case 4:
|
||||
str = "Disconnecting";
|
||||
break;
|
||||
case 5:
|
||||
str = "Disconnected";
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* $Id: getconnstatus.h,v 1.2 2011/05/23 20:22: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 __GETCONNSTATUS_H__
|
||||
#define __GETCONNSTATUS_H__
|
||||
|
||||
/**
|
||||
* get the connection status
|
||||
* return values :
|
||||
* 0 - Unconfigured
|
||||
* 1 - Connecting
|
||||
* 2 - Connected
|
||||
* 3 - PendingDisconnect
|
||||
* 4 - Disconnecting
|
||||
* 5 - Disconnected */
|
||||
int
|
||||
get_wan_connection_status(const char * ifname);
|
||||
|
||||
/**
|
||||
* return the same value as get_wan_connection_status()
|
||||
* as a C string */
|
||||
const char *
|
||||
get_wan_connection_status_str(const char * ifname);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/* $Id: getifaddr.c,v 1.11 2011/05/15 08:59:27 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#if defined(sun)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "getifaddr.h"
|
||||
#if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
getifaddr(const char * ifname, char * buf, int len)
|
||||
{
|
||||
#ifndef USE_GETIFADDRS
|
||||
/* use ioctl SIOCGIFADDR. Works only for ip v4 */
|
||||
/* SIOCGIFADDR struct ifreq * */
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
int ifrlen;
|
||||
struct sockaddr_in * addr;
|
||||
ifrlen = sizeof(ifr);
|
||||
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m");
|
||||
return -1;
|
||||
}
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
if(!inet_ntop(AF_INET, &addr->sin_addr, buf, len))
|
||||
{
|
||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
#else /* ifndef USE_GETIFADDRS */
|
||||
/* Works for all address families (both ip v4 and ip v6) */
|
||||
struct ifaddrs * ifap;
|
||||
struct ifaddrs * ife;
|
||||
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
if(getifaddrs(&ifap)<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifaddrs: %m");
|
||||
return -1;
|
||||
}
|
||||
for(ife = ifap; ife; ife = ife->ifa_next)
|
||||
{
|
||||
/* skip other interfaces */
|
||||
if(0 != strcmp(ifname, ife->ifa_name))
|
||||
continue;
|
||||
switch(ife->ifa_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
inet_ntop(ife->ifa_addr->sa_family,
|
||||
&((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
||||
buf, len);
|
||||
break;
|
||||
/*
|
||||
case AF_INET6:
|
||||
inet_ntop(ife->ifa_addr->sa_family,
|
||||
&((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr,
|
||||
buf, len);
|
||||
*/
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
int
|
||||
find_ipv6_addr(const char * ifname,
|
||||
char * dst, int n)
|
||||
{
|
||||
struct ifaddrs * ifap;
|
||||
struct ifaddrs * ife;
|
||||
const struct sockaddr_in6 * addr;
|
||||
char buf[64];
|
||||
int r = 0;
|
||||
|
||||
if(!dst)
|
||||
return -1;
|
||||
|
||||
if(getifaddrs(&ifap)<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifaddrs: %m");
|
||||
return -1;
|
||||
}
|
||||
for(ife = ifap; ife; ife = ife->ifa_next)
|
||||
{
|
||||
/* skip other interfaces if one was specified */
|
||||
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||
continue;
|
||||
if(ife->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
addr = (const struct sockaddr_in6 *)ife->ifa_addr;
|
||||
if(!IN6_IS_ADDR_LOOPBACK(&addr->sin6_addr)
|
||||
&& !IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
|
||||
{
|
||||
inet_ntop(ife->ifa_addr->sa_family,
|
||||
&addr->sin6_addr,
|
||||
buf, sizeof(buf));
|
||||
/* add brackets */
|
||||
snprintf(dst, n, "[%s]", buf);
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* $Id: getifaddr.h,v 1.5 2011/05/15 08:59:27 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 __GETIFADDR_H__
|
||||
#define __GETIFADDR_H__
|
||||
|
||||
/* getifaddr()
|
||||
* take a network interface name and write the
|
||||
* ip v4 address as text in the buffer
|
||||
* returns: 0 success, -1 failure */
|
||||
int
|
||||
getifaddr(const char * ifname, char * buf, int len);
|
||||
|
||||
/* find a non link local IP v6 address for the interface.
|
||||
* if ifname is NULL, look for all interfaces */
|
||||
int
|
||||
find_ipv6_addr(const char * ifname,
|
||||
char * dst, int n);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2008 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef __GETIFSTATS_H__
|
||||
#define __GETIFSTATS_H__
|
||||
|
||||
struct ifdata {
|
||||
unsigned long opackets;
|
||||
unsigned long ipackets;
|
||||
unsigned long obytes;
|
||||
unsigned long ibytes;
|
||||
unsigned long baudrate;
|
||||
};
|
||||
|
||||
/* getifstats()
|
||||
* Fill the ifdata structure with statistics for network interface ifname.
|
||||
* Return 0 in case of success, -1 for bad arguments or any error */
|
||||
int
|
||||
getifstats(const char * ifname, struct ifdata * data);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/* $Id: ifacewatcher.h,v 1.2 2011/05/20 09:42:49 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2009 Thomas Bernard
|
||||
*
|
||||
* ifacewatcher.h
|
||||
*
|
||||
* This file implements dynamic serving of new network interfaces
|
||||
* which weren't available during daemon start. It also takes care
|
||||
* of interfaces which become unavailable.
|
||||
*
|
||||
* Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
|
||||
* 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. */
|
||||
|
||||
#ifndef __IFACEWATCHER_H__
|
||||
#define __IFACEWATCHER_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_IFACEWATCHER
|
||||
int OpenAndConfInterfaceWatchSocket(void);
|
||||
void ProcessInterfaceWatchNotify(int s);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,16 @@
|
|||
# $Id: Makefile,v 1.1 2007/09/25 19:44:43 nanard Exp $
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -g -I.
|
||||
|
||||
all: testipfrdr
|
||||
|
||||
clean:
|
||||
rm *.o testipfrdr
|
||||
|
||||
testipfrdr: testipfrdr.o ipfrdr.o
|
||||
$(CC) -o $@ $^
|
||||
|
||||
ipfrdr.o: ipfrdr.c
|
||||
|
||||
testipfrdr.o: testipfrdr.c
|
||||
|
|
@ -0,0 +1,602 @@
|
|||
/* $Id: ipfrdr.c,v 1.11 2009/10/10 18:34:39 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2007 Darren Reed
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
/*
|
||||
* This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
|
||||
* Needed here because on some systems <sys/uio.h> gets included by things
|
||||
* like <sys/socket.h>
|
||||
*/
|
||||
#ifndef _KERNEL
|
||||
# define ADD_KERNEL
|
||||
# define _KERNEL
|
||||
# define KERNEL
|
||||
#endif
|
||||
#ifdef __OpenBSD__
|
||||
struct file;
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
#ifdef ADD_KERNEL
|
||||
# undef _KERNEL
|
||||
# undef KERNEL
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#if __FreeBSD_version >= 300000
|
||||
# include <net/if_var.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#ifndef TCP_PAWS_IDLE /* IRIX */
|
||||
# include <netinet/tcp.h>
|
||||
#endif
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#if !defined(__SVR4) && !defined(__svr4__) && defined(sun)
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "netinet/ipl.h"
|
||||
#include "netinet/ip_compat.h"
|
||||
#include "netinet/ip_fil.h"
|
||||
#include "netinet/ip_nat.h"
|
||||
#include "netinet/ip_state.h"
|
||||
|
||||
|
||||
#ifndef __P
|
||||
# ifdef __STDC__
|
||||
# define __P(x) x
|
||||
# else
|
||||
# define __P(x) ()
|
||||
# endif
|
||||
#endif
|
||||
#ifndef __STDC__
|
||||
# undef const
|
||||
# define const
|
||||
#endif
|
||||
|
||||
#ifndef U_32_T
|
||||
# define U_32_T 1
|
||||
# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
|
||||
defined(__sgi)
|
||||
typedef u_int32_t u_32_t;
|
||||
# else
|
||||
# if defined(__alpha__) || defined(__alpha) || defined(_LP64)
|
||||
typedef unsigned int u_32_t;
|
||||
# else
|
||||
# if SOLARIS2 >= 6
|
||||
typedef uint32_t u_32_t;
|
||||
# else
|
||||
typedef unsigned int u_32_t;
|
||||
# endif
|
||||
# endif
|
||||
# endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */
|
||||
#endif /* U_32_T */
|
||||
|
||||
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) || \
|
||||
(_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
|
||||
SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux)
|
||||
# include <stdarg.h>
|
||||
typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...));
|
||||
#else
|
||||
typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *));
|
||||
#endif
|
||||
typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *));
|
||||
typedef int (* copyfunc_t) __P((void *, void *, size_t));
|
||||
|
||||
|
||||
/*
|
||||
* SunOS4
|
||||
*/
|
||||
#if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
|
||||
extern int ioctl __P((int, int, void *));
|
||||
#endif
|
||||
|
||||
#include "../upnpglobalvars.h"
|
||||
|
||||
/* group name */
|
||||
static const char group_name[] = "miniupnpd";
|
||||
|
||||
static int dev = -1;
|
||||
static int dev_ipl = -1;
|
||||
|
||||
/* IPFilter cannot store redirection descriptions, so we use our
|
||||
* own structure to store them */
|
||||
struct rdr_desc {
|
||||
struct rdr_desc * next;
|
||||
unsigned short eport;
|
||||
int proto;
|
||||
char str[];
|
||||
};
|
||||
|
||||
/* pointer to the chained list where descriptions are stored */
|
||||
static struct rdr_desc * rdr_desc_list;
|
||||
|
||||
static void
|
||||
add_redirect_desc(unsigned short eport, int proto, const char * desc)
|
||||
{
|
||||
struct rdr_desc * p;
|
||||
size_t l;
|
||||
|
||||
if (desc != NULL) {
|
||||
l = strlen(desc) + 1;
|
||||
p = malloc(sizeof(struct rdr_desc) + l);
|
||||
if (p) {
|
||||
p->next = rdr_desc_list;
|
||||
p->eport = eport;
|
||||
p->proto = proto;
|
||||
memcpy(p->str, desc, l);
|
||||
rdr_desc_list = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
del_redirect_desc(unsigned short eport, int proto)
|
||||
{
|
||||
struct rdr_desc * p, * last;
|
||||
|
||||
last = NULL;
|
||||
for (p = rdr_desc_list; p; p = p->next) {
|
||||
if(p->eport == eport && p->proto == proto) {
|
||||
if (last == NULL)
|
||||
rdr_desc_list = p->next;
|
||||
else
|
||||
last->next = p->next;
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_redirect_desc(unsigned short eport, int proto, char * desc, int desclen)
|
||||
{
|
||||
struct rdr_desc * p;
|
||||
|
||||
if (desc == NULL || desclen == 0)
|
||||
return;
|
||||
for (p = rdr_desc_list; p; p = p->next) {
|
||||
if (p->eport == eport && p->proto == proto)
|
||||
{
|
||||
strncpy(desc, p->str, desclen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int init_redirect(void)
|
||||
{
|
||||
|
||||
dev = open(IPNAT_NAME, O_RDWR);
|
||||
if (dev < 0) {
|
||||
syslog(LOG_ERR, "open(\"%s\"): %m", IPNAT_NAME);
|
||||
return -1;
|
||||
}
|
||||
dev_ipl = open(IPL_NAME, O_RDWR);
|
||||
if (dev_ipl < 0) {
|
||||
syslog(LOG_ERR, "open(\"%s\"): %m", IPL_NAME);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shutdown_redirect(void)
|
||||
{
|
||||
|
||||
if (dev >= 0) {
|
||||
close(dev);
|
||||
dev = -1;
|
||||
}
|
||||
if (dev_ipl >= 0) {
|
||||
close(dev_ipl);
|
||||
dev = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
add_redirect_rule2(const char * ifname, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport, int proto,
|
||||
const char * desc)
|
||||
{
|
||||
struct ipnat ipnat;
|
||||
struct ipfobj obj;
|
||||
int r;
|
||||
|
||||
if (dev < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPNAT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
memset(&ipnat, 0, sizeof(ipnat));
|
||||
|
||||
ipnat.in_redir = NAT_REDIRECT;
|
||||
ipnat.in_p = proto;
|
||||
if (proto == IPPROTO_TCP)
|
||||
ipnat.in_flags = IPN_TCP;
|
||||
if (proto == IPPROTO_UDP)
|
||||
ipnat.in_flags = IPN_UDP;
|
||||
ipnat.in_dcmp = FR_EQUAL;
|
||||
ipnat.in_pmin = htons(eport);
|
||||
ipnat.in_pmax = htons(eport);
|
||||
ipnat.in_pnext = htons(iport);
|
||||
ipnat.in_v = 4;
|
||||
strlcpy(ipnat.in_tag.ipt_tag, group_name, IPFTAG_LEN);
|
||||
|
||||
#ifdef USE_IFNAME_IN_RULES
|
||||
if (ifname) {
|
||||
strlcpy(ipnat.in_ifnames[0], ifname, IFNAMSIZ);
|
||||
strlcpy(ipnat.in_ifnames[1], ifname, IFNAMSIZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
inet_pton(AF_INET, iaddr, &ipnat.in_in[0].in4);
|
||||
ipnat.in_in[1].in4.s_addr = 0xffffffff;
|
||||
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_size = sizeof(ipnat);
|
||||
obj.ipfo_ptr = &ipnat;
|
||||
obj.ipfo_type = IPFOBJ_IPNAT;
|
||||
|
||||
r = ioctl(dev, SIOCADNAT, &obj);
|
||||
if (r == -1)
|
||||
syslog(LOG_ERR, "ioctl(SIOCADNAT): %m");
|
||||
else
|
||||
add_redirect_desc(eport, proto, desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* get_redirect_rule()
|
||||
* return value : 0 success (found)
|
||||
* -1 = error or rule not found */
|
||||
int
|
||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes)
|
||||
{
|
||||
ipfgeniter_t iter;
|
||||
ipfobj_t obj;
|
||||
ipnat_t ipn;
|
||||
int r;
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_type = IPFOBJ_GENITER;
|
||||
obj.ipfo_size = sizeof(iter);
|
||||
obj.ipfo_ptr = &iter;
|
||||
|
||||
iter.igi_type = IPFGENITER_IPNAT;
|
||||
#if IPFILTER_VERSION > 4011300
|
||||
iter.igi_nitems = 1;
|
||||
#endif
|
||||
iter.igi_data = &ipn;
|
||||
|
||||
if (dev < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPNAT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = -1;
|
||||
do {
|
||||
if (ioctl(dev, SIOCGENITER, &obj) == -1) {
|
||||
syslog(LOG_ERR, "ioctl(dev, SIOCGENITER): %m");
|
||||
break;
|
||||
}
|
||||
if (eport == ntohs(ipn.in_pmin) &&
|
||||
eport == ntohs(ipn.in_pmax) &&
|
||||
strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
|
||||
ipn.in_p == proto)
|
||||
{
|
||||
strlcpy(desc, "", desclen);
|
||||
if (packets != NULL)
|
||||
*packets = 0;
|
||||
if (bytes != NULL)
|
||||
*bytes = 0;
|
||||
if (iport != NULL)
|
||||
*iport = ntohs(ipn.in_pnext);
|
||||
if (desc != NULL)
|
||||
get_redirect_desc(eport, proto, desc, desclen);
|
||||
inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
|
||||
r = 0;
|
||||
}
|
||||
} while (ipn.in_next != NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
get_redirect_rule_by_index(int index,
|
||||
char * ifname, unsigned short * eport,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
int * proto, char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes)
|
||||
{
|
||||
ipfgeniter_t iter;
|
||||
ipfobj_t obj;
|
||||
ipnat_t ipn;
|
||||
int n, r;
|
||||
|
||||
if (index < 0)
|
||||
return -1;
|
||||
|
||||
if (dev < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPNAT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_ptr = &iter;
|
||||
obj.ipfo_size = sizeof(iter);
|
||||
obj.ipfo_type = IPFOBJ_GENITER;
|
||||
|
||||
iter.igi_type = IPFGENITER_IPNAT;
|
||||
#if IPFILTER_VERSION > 4011300
|
||||
iter.igi_nitems = 1;
|
||||
#endif
|
||||
iter.igi_data = &ipn;
|
||||
|
||||
n = 0;
|
||||
r = -1;
|
||||
do {
|
||||
if (ioctl(dev, SIOCGENITER, &obj) == -1) {
|
||||
syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
|
||||
"get_redirect_rule_by_index");
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
|
||||
continue;
|
||||
|
||||
if (index == n++) {
|
||||
*proto = ipn.in_p;
|
||||
*eport = ntohs(ipn.in_pmax);
|
||||
*iport = ntohs(ipn.in_pnext);
|
||||
|
||||
if (ifname)
|
||||
strlcpy(ifname, ipn.in_ifnames[0], IFNAMSIZ);
|
||||
if (packets != NULL)
|
||||
*packets = 0;
|
||||
if (bytes != NULL)
|
||||
*bytes = 0;
|
||||
if (desc != NULL)
|
||||
get_redirect_desc(*eport, *proto, desc, desclen);
|
||||
inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
|
||||
r = 0;
|
||||
}
|
||||
} while (ipn.in_next != NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
real_delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
|
||||
{
|
||||
ipfgeniter_t iter;
|
||||
ipfobj_t obj;
|
||||
ipnat_t ipn;
|
||||
int r;
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_type = IPFOBJ_GENITER;
|
||||
obj.ipfo_size = sizeof(iter);
|
||||
obj.ipfo_ptr = &iter;
|
||||
|
||||
iter.igi_type = IPFGENITER_IPNAT;
|
||||
#if IPFILTER_VERSION > 4011300
|
||||
iter.igi_nitems = 1;
|
||||
#endif
|
||||
iter.igi_data = &ipn;
|
||||
|
||||
if (dev < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPNAT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = -1;
|
||||
do {
|
||||
if (ioctl(dev, SIOCGENITER, &obj) == -1) {
|
||||
syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
|
||||
"delete_redirect_rule");
|
||||
break;
|
||||
}
|
||||
if (eport == ntohs(ipn.in_pmin) &&
|
||||
eport == ntohs(ipn.in_pmax) &&
|
||||
strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
|
||||
ipn.in_p == proto)
|
||||
{
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_size = sizeof(ipn);
|
||||
obj.ipfo_ptr = &ipn;
|
||||
obj.ipfo_type = IPFOBJ_IPNAT;
|
||||
r = ioctl(dev, SIOCRMNAT, &obj);
|
||||
if (r == -1)
|
||||
syslog(LOG_ERR, "%s:ioctl(SIOCRMNAT): %m",
|
||||
"delete_redirect_rule");
|
||||
/* Delete the desc even if the above failed */
|
||||
del_redirect_desc(eport, proto);
|
||||
break;
|
||||
}
|
||||
} while (ipn.in_next != NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME: For some reason, the iter isn't reset every other delete,
|
||||
* so we attempt 2 deletes. */
|
||||
int
|
||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = real_delete_redirect_rule(ifname, eport, proto);
|
||||
if (r == -1)
|
||||
r = real_delete_redirect_rule(ifname, eport, proto);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* thanks to Seth Mos for this function */
|
||||
int
|
||||
add_filter_rule2(const char * ifname, const char * iaddr,
|
||||
unsigned short eport, unsigned short iport,
|
||||
int proto, const char * desc)
|
||||
{
|
||||
ipfobj_t obj;
|
||||
frentry_t fr;
|
||||
fripf_t ipffr;
|
||||
int r;
|
||||
|
||||
if (dev_ipl < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPL_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
memset(&fr, 0, sizeof(fr));
|
||||
memset(&ipffr, 0, sizeof(ipffr));
|
||||
|
||||
fr.fr_flags = FR_PASS|FR_KEEPSTATE|FR_QUICK|FR_INQUE;
|
||||
if (GETFLAG(LOGPACKETSMASK))
|
||||
fr.fr_flags |= FR_LOG|FR_LOGFIRST;
|
||||
fr.fr_v = 4;
|
||||
|
||||
fr.fr_type = FR_T_IPF;
|
||||
fr.fr_dun.fru_ipf = &ipffr;
|
||||
fr.fr_dsize = sizeof(ipffr);
|
||||
fr.fr_isc = (void *)-1;
|
||||
|
||||
fr.fr_proto = proto;
|
||||
fr.fr_mproto = 0xff;
|
||||
fr.fr_dcmp = FR_EQUAL;
|
||||
fr.fr_dport = eport;
|
||||
#ifdef USE_IFNAME_IN_RULES
|
||||
if (ifname)
|
||||
strlcpy(fr.fr_ifnames[0], ifname, IFNAMSIZ);
|
||||
#endif
|
||||
strlcpy(fr.fr_group, group_name, sizeof(fr.fr_group));
|
||||
|
||||
if (proto == IPPROTO_TCP) {
|
||||
fr.fr_tcpf = TH_SYN;
|
||||
fr.fr_tcpfm = TH_SYN|TH_ACK|TH_RST|TH_FIN|TH_URG|TH_PUSH;
|
||||
}
|
||||
|
||||
inet_pton(AF_INET, iaddr, &fr.fr_daddr);
|
||||
fr.fr_dmask = 0xffffffff;
|
||||
|
||||
obj.ipfo_rev = IPFILTER_VERSION;
|
||||
obj.ipfo_ptr = &fr;
|
||||
obj.ipfo_size = sizeof(fr);
|
||||
|
||||
r = ioctl(dev_ipl, SIOCINAFR, &obj);
|
||||
if (r == -1) {
|
||||
if (errno == ESRCH)
|
||||
syslog(LOG_ERR,
|
||||
"SIOCINAFR(missing 'head %s' rule?):%m",
|
||||
group_name);
|
||||
else
|
||||
syslog(LOG_ERR, "SIOCINAFR:%m");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
delete_filter_rule(const char * ifname, unsigned short eport, int proto)
|
||||
{
|
||||
ipfobj_t wobj, dobj;
|
||||
ipfruleiter_t rule;
|
||||
u_long darray[1000];
|
||||
u_long array[1000];
|
||||
friostat_t fio;
|
||||
frentry_t *fp;
|
||||
int r;
|
||||
|
||||
if (dev_ipl < 0) {
|
||||
syslog(LOG_ERR, "%s not open", IPL_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wobj.ipfo_rev = IPFILTER_VERSION;
|
||||
wobj.ipfo_type = IPFOBJ_IPFSTAT;
|
||||
wobj.ipfo_size = sizeof(fio);
|
||||
wobj.ipfo_ptr = &fio;
|
||||
|
||||
if (ioctl(dev_ipl, SIOCGETFS, &wobj) == -1) {
|
||||
syslog(LOG_ERR, "ioctl(SIOCGETFS): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wobj.ipfo_rev = IPFILTER_VERSION;
|
||||
wobj.ipfo_ptr = &rule;
|
||||
wobj.ipfo_size = sizeof(rule);
|
||||
wobj.ipfo_type = IPFOBJ_IPFITER;
|
||||
|
||||
fp = (frentry_t *)array;
|
||||
fp->fr_dun.fru_data = darray;
|
||||
fp->fr_dsize = sizeof(darray);
|
||||
|
||||
rule.iri_inout = 0;
|
||||
rule.iri_active = fio.f_active;
|
||||
#if IPFILTER_VERSION > 4011300
|
||||
rule.iri_nrules = 1;
|
||||
rule.iri_v = 4;
|
||||
#endif
|
||||
rule.iri_rule = fp;
|
||||
strlcpy(rule.iri_group, group_name, sizeof(rule.iri_group));
|
||||
|
||||
dobj.ipfo_rev = IPFILTER_VERSION;
|
||||
dobj.ipfo_size = sizeof(*fp);
|
||||
dobj.ipfo_type = IPFOBJ_FRENTRY;
|
||||
|
||||
r = -1;
|
||||
do {
|
||||
memset(array, 0xff, sizeof(array));
|
||||
|
||||
if (ioctl(dev_ipl, SIOCIPFITER, &wobj) == -1) {
|
||||
syslog(LOG_ERR, "ioctl(SIOCIPFITER): %m");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fp->fr_data != NULL)
|
||||
fp->fr_data = (char *)fp + sizeof(*fp);
|
||||
if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
|
||||
fp->fr_dport == eport &&
|
||||
fp->fr_proto == proto)
|
||||
{
|
||||
dobj.ipfo_ptr = fp;
|
||||
|
||||
r = ioctl(dev_ipl, SIOCRMAFR, &dobj);
|
||||
if (r == -1)
|
||||
syslog(LOG_ERR, "ioctl(SIOCRMAFR): %m");
|
||||
break;
|
||||
}
|
||||
} while (fp->fr_next != NULL);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/* $Id: ipfrdr.h,v 1.3 2007/11/02 22:54:01 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2007 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef __IPFRDR_H__
|
||||
#define __IPFRDR_H__
|
||||
|
||||
#include "../commonrdr.h"
|
||||
|
||||
int
|
||||
add_redirect_rule2(const char * ifname, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport, int proto,
|
||||
const char * desc);
|
||||
|
||||
int
|
||||
add_filter_rule2(const char * ifname, const char * iaddr,
|
||||
unsigned short eport, unsigned short iport,
|
||||
int proto, const char * desc);
|
||||
|
||||
|
||||
/* get_redirect_rule() gets internal IP and port from
|
||||
* interface, external port and protocl
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
|
||||
int
|
||||
get_redirect_rule_by_index(int index,
|
||||
char * ifname, unsigned short * eport,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
int * proto, char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
#endif
|
||||
|
||||
/* delete_redirect_rule()
|
||||
*/
|
||||
int
|
||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
/* delete_filter_rule()
|
||||
*/
|
||||
int
|
||||
delete_filter_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
int
|
||||
clear_redirect_rules(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* $Id: testipfrdr.c,v 1.3 2007/10/01 16:21:23 nanard Exp $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include "ipfrdr.h"
|
||||
|
||||
extern void
|
||||
test_list_nat_rules();
|
||||
/* test program for ipfrdr.c */
|
||||
|
||||
int
|
||||
main(int argc, char * * argv)
|
||||
{
|
||||
openlog("testipfrdrd", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||
printf("List nat rules :\n");
|
||||
test_list_nat_rules();
|
||||
printf("Add redirection !\n");
|
||||
add_redirect_rule2("ep0", 12345, "1.2.3.4", 54321, IPPROTO_UDP,
|
||||
"redirection description");
|
||||
printf("List nat rules :\n");
|
||||
test_list_nat_rules();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# $Id: Makefile,v 1.2 2009/08/20 09:31:10 nanard Exp $
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -g -I.
|
||||
RM=rm -f
|
||||
|
||||
all: testipfwrdr
|
||||
|
||||
clean:
|
||||
$(RM) *.o testipfwrdr
|
||||
|
||||
testipfwrdr: testipfwrdr.o ipfwrdr.o
|
||||
$(CC) -o $@ $^
|
||||
|
||||
ipfwrdr.o: ipfwrdr.c
|
||||
|
||||
testipfwrdr.o: testipfwrdr.c
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/* $Id: ipfwaux.h,v 1.3 2011/02/20 23:43:41 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009 Jardel Weyrich
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
#ifndef __IPFWAUX_H__
|
||||
#define __IPFWAUX_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
|
||||
#define IP_FW_BASE (IP_FW_ADD - 5)
|
||||
#define IP_FW_INIT (IP_FW_BASE + 1)
|
||||
#define IP_FW_TERM (IP_FW_BASE + 2)
|
||||
|
||||
static int ipfw_exec(int optname, void * optval, uintptr_t optlen) {
|
||||
static int sock = -1;
|
||||
int result;
|
||||
|
||||
switch (optname) {
|
||||
case IP_FW_INIT:
|
||||
if (sock == -1)
|
||||
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (sock < 0) {
|
||||
syslog(LOG_ERR, "socket(SOCK_RAW): %m");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case IP_FW_TERM:
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
case IP_FW_ADD:
|
||||
case IP_FW_DEL:
|
||||
result = setsockopt(sock, IPPROTO_IP, optname, optval, optlen);
|
||||
if (result == -1) {
|
||||
syslog(LOG_ERR, "setsockopt(): %m");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case IP_FW_GET:
|
||||
result = getsockopt(sock, IPPROTO_IP, optname, optval, (socklen_t *)optlen);
|
||||
if (result == -1) {
|
||||
syslog(LOG_ERR, "getsockopt(): %m");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "unhandled option");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipfw_free_ruleset(struct ip_fw ** rules) {
|
||||
if (rules == NULL || *rules == NULL)
|
||||
return;
|
||||
free(*rules);
|
||||
*rules = NULL;
|
||||
}
|
||||
|
||||
static int ipfw_fetch_ruleset(struct ip_fw ** rules, int * total_fetched, int count) {
|
||||
int fetched;
|
||||
socklen_t size;
|
||||
|
||||
if (rules == NULL || *total_fetched < 0 || count < 1)
|
||||
return -1;
|
||||
|
||||
size = sizeof(struct ip_fw) * (*total_fetched + count);
|
||||
*rules = (struct ip_fw *)realloc(*rules, size);
|
||||
if (*rules == NULL) {
|
||||
syslog(LOG_ERR, "realloc(): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*rules)->version = IP_FW_CURRENT_API_VERSION;
|
||||
if (ipfw_exec(IP_FW_GET, *rules, (uintptr_t)&size) < 0)
|
||||
return -1;
|
||||
fetched = *total_fetched;
|
||||
*total_fetched = size / sizeof(struct ip_fw);
|
||||
|
||||
return *total_fetched - fetched;
|
||||
}
|
||||
|
||||
static int ipfw_validate_protocol(int value) {
|
||||
switch (value) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_UDP:
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "invalid protocol");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipfw_validate_ifname(const char * const value) {
|
||||
int len = strlen(value);
|
||||
if (len < 2 || len > FW_IFNLEN) {
|
||||
syslog(LOG_ERR, "invalid interface name");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,467 @@
|
|||
/* $Id: ipfwrdr.c,v 1.11 2011/07/12 19:17:05 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009 Jardel Weyrich
|
||||
* (c) 2011 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
//
|
||||
// This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
|
||||
// Needed here because on some systems <sys/uio.h> gets included by things
|
||||
// like <sys/socket.h>
|
||||
//
|
||||
#ifndef _KERNEL
|
||||
# define ADD_KERNEL
|
||||
# define _KERNEL
|
||||
# define KERNEL
|
||||
#endif
|
||||
#ifdef __OpenBSD__
|
||||
struct file;
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
#ifdef ADD_KERNEL
|
||||
# undef _KERNEL
|
||||
# undef KERNEL
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#if __FreeBSD_version >= 300000
|
||||
# include <net/if_var.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip_fw.h>
|
||||
#include "ipfwaux.h"
|
||||
#include "ipfwrdr.h"
|
||||
|
||||
#include "../upnpglobalvars.h"
|
||||
|
||||
/* init and shutdown functions */
|
||||
|
||||
int init_redirect(void) {
|
||||
return ipfw_exec(IP_FW_INIT, NULL, 0);
|
||||
}
|
||||
|
||||
void shutdown_redirect(void) {
|
||||
ipfw_exec(IP_FW_TERM, NULL, 0);
|
||||
}
|
||||
|
||||
/* ipfw cannot store descriptions and timestamp for port mappings so we keep
|
||||
* our own list in memory */
|
||||
struct mapping_desc_time {
|
||||
struct mapping_desc_time * next;
|
||||
unsigned int timestamp;
|
||||
unsigned short eport;
|
||||
short proto;
|
||||
char desc[];
|
||||
};
|
||||
|
||||
static struct mapping_desc_time * mappings_list = NULL;
|
||||
|
||||
/* add an element to the port mappings descriptions & timestamp list */
|
||||
static void
|
||||
add_desc_time(unsigned short eport, int proto,
|
||||
const char * desc, unsigned int timestamp)
|
||||
{
|
||||
struct mapping_desc_time * tmp;
|
||||
size_t l;
|
||||
if(!desc)
|
||||
desc = "miniupnpd";
|
||||
l = strlen(desc) + 1;
|
||||
tmp = malloc(sizeof(struct mapping_desc_time) + l);
|
||||
if(tmp) {
|
||||
/* fill the element and insert it as head of the list */
|
||||
tmp->next = mappings_list;
|
||||
tmp->timestamp = timestamp;
|
||||
tmp->eport = eport;
|
||||
tmp->proto = (short)proto;
|
||||
memcpy(tmp->desc, desc, l);
|
||||
mappings_list = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove an element to the port mappings descriptions & timestamp list */
|
||||
static void
|
||||
del_desc_time(unsigned short eport, int proto)
|
||||
{
|
||||
struct mapping_desc_time * e;
|
||||
struct mapping_desc_time * * p;
|
||||
p = &mappings_list;
|
||||
e = *p;
|
||||
while(e) {
|
||||
if(e->eport == eport && e->proto == (short)proto) {
|
||||
*p = e->next;
|
||||
free(e);
|
||||
return;
|
||||
} else {
|
||||
p = &e->next;
|
||||
e = *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* go through the list and find the description and timestamp */
|
||||
static void
|
||||
get_desc_time(unsigned short eport, int proto,
|
||||
char * desc, int desclen,
|
||||
unsigned int * timestamp)
|
||||
{
|
||||
struct mapping_desc_time * e;
|
||||
|
||||
for(e = mappings_list; e; e = e->next) {
|
||||
if(e->eport == eport && e->proto == (short)proto) {
|
||||
if(desc)
|
||||
strlcpy(desc, e->desc, desclen);
|
||||
if(timestamp)
|
||||
*timestamp = e->timestamp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- */
|
||||
int add_redirect_rule2(
|
||||
const char * ifname,
|
||||
const char * rhost,
|
||||
unsigned short eport,
|
||||
const char * iaddr,
|
||||
unsigned short iport,
|
||||
int proto,
|
||||
const char * desc,
|
||||
unsigned int timestamp)
|
||||
{
|
||||
struct ip_fw rule;
|
||||
int r;
|
||||
|
||||
if (ipfw_validate_protocol(proto) < 0)
|
||||
return -1;
|
||||
if (ipfw_validate_ifname(ifname) < 0)
|
||||
return -1;
|
||||
|
||||
memset(&rule, 0, sizeof(struct ip_fw));
|
||||
rule.version = IP_FW_CURRENT_API_VERSION;
|
||||
//rule.fw_number = 1000; // rule number
|
||||
//rule.context = (void *)desc; // The description is kept in a separate list
|
||||
rule.fw_prot = proto; // protocol
|
||||
rule.fw_flg |= IP_FW_F_IIFACE; // interfaces to check
|
||||
rule.fw_flg |= IP_FW_F_IIFNAME; // interfaces to check by name
|
||||
rule.fw_flg |= (IP_FW_F_IN | IP_FW_F_OUT); // packet direction
|
||||
rule.fw_flg |= IP_FW_F_FWD; // forward action
|
||||
#ifdef USE_IFNAME_IN_RULES
|
||||
if (ifname != NULL) {
|
||||
strlcpy(rule.fw_in_if.fu_via_if.name, ifname, IFNAMSIZ); // src interface
|
||||
rule.fw_in_if.fu_via_if.unit = -1;
|
||||
}
|
||||
#endif
|
||||
if (inet_aton(iaddr, &rule.fw_out_if.fu_via_ip) == 0) {
|
||||
syslog(LOG_ERR, "inet_aton(): %m");
|
||||
return -1;
|
||||
}
|
||||
memcpy(&rule.fw_dst, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
|
||||
memcpy(&rule.fw_fwd_ip.sin_addr, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
|
||||
rule.fw_dmsk.s_addr = INADDR_BROADCAST; //TODO check this
|
||||
IP_FW_SETNDSTP(&rule, 1); // number of external ports
|
||||
rule.fw_uar.fw_pts[0] = eport; // external port
|
||||
rule.fw_fwd_ip.sin_port = iport; // internal port
|
||||
if (rhost && rhost[0] != '\0') {
|
||||
inet_aton(rhost, &rule.fw_src);
|
||||
rule.fw_smsk.s_addr = htonl(INADDR_NONE);
|
||||
}
|
||||
|
||||
r = ipfw_exec(IP_FW_ADD, &rule, sizeof(rule));
|
||||
if(r >= 0)
|
||||
add_desc_time(eport, proto, desc, timestamp);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* get_redirect_rule()
|
||||
* return value : 0 success (found)
|
||||
* -1 = error or rule not found */
|
||||
int get_redirect_rule(
|
||||
const char * ifname,
|
||||
unsigned short eport,
|
||||
int proto,
|
||||
char * iaddr,
|
||||
int iaddrlen,
|
||||
unsigned short * iport,
|
||||
char * desc,
|
||||
int desclen,
|
||||
char * rhost,
|
||||
int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets,
|
||||
u_int64_t * bytes)
|
||||
{
|
||||
int i, count_rules, total_rules = 0;
|
||||
struct ip_fw * rules = NULL;
|
||||
|
||||
if (ipfw_validate_protocol(proto) < 0)
|
||||
return -1;
|
||||
if (ipfw_validate_ifname(ifname) < 0)
|
||||
return -1;
|
||||
if (timestamp)
|
||||
*timestamp = 0;
|
||||
|
||||
do {
|
||||
count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
|
||||
if (count_rules < 0)
|
||||
goto error;
|
||||
} while (count_rules == 10);
|
||||
|
||||
for (i=0; i<total_rules-1; i++) {
|
||||
const struct ip_fw const * ptr = &rules[i];
|
||||
if (proto == ptr->fw_prot && eport == ptr->fw_uar.fw_pts[0]) {
|
||||
if (packets != NULL)
|
||||
*packets = ptr->fw_pcnt;
|
||||
if (bytes != NULL)
|
||||
*bytes = ptr->fw_bcnt;
|
||||
if (iport != NULL)
|
||||
*iport = ptr->fw_fwd_ip.sin_port;
|
||||
if (iaddr != NULL && iaddrlen > 0) {
|
||||
/* looks like fw_out_if.fu_via_ip is zero */
|
||||
//if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
|
||||
if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
|
||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (rhost != NULL && rhostlen > 0) {
|
||||
if (ptr->fw_src.s_addr == 0)
|
||||
rhost[0] = '\0';
|
||||
else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
|
||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
// And what if we found more than 1 matching rule?
|
||||
ipfw_free_ruleset(&rules);
|
||||
get_desc_time(eport, proto, desc, desclen, timestamp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
if (rules != NULL)
|
||||
ipfw_free_ruleset(&rules);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int delete_redirect_rule(
|
||||
const char * ifname,
|
||||
unsigned short eport,
|
||||
int proto)
|
||||
{
|
||||
int i, count_rules, total_rules = 0;
|
||||
struct ip_fw * rules = NULL;
|
||||
|
||||
if (ipfw_validate_protocol(proto) < 0)
|
||||
return -1;
|
||||
if (ipfw_validate_ifname(ifname) < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
|
||||
if (count_rules < 0)
|
||||
goto error;
|
||||
} while (count_rules == 10);
|
||||
|
||||
for (i=0; i<total_rules-1; i++) {
|
||||
const struct ip_fw const * ptr = &rules[i];
|
||||
if (proto == ptr->fw_prot && eport == ptr->fw_uar.fw_pts[0]) {
|
||||
if (ipfw_exec(IP_FW_DEL, (struct ip_fw *)ptr, sizeof(*ptr)) < 0)
|
||||
goto error;
|
||||
// And what if we found more than 1 matching rule?
|
||||
ipfw_free_ruleset(&rules);
|
||||
del_desc_time(eport, proto);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
if (rules != NULL)
|
||||
ipfw_free_ruleset(&rules);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int add_filter_rule2(
|
||||
const char * ifname,
|
||||
const char * rhost,
|
||||
const char * iaddr,
|
||||
unsigned short eport,
|
||||
unsigned short iport,
|
||||
int proto,
|
||||
const char * desc)
|
||||
{
|
||||
//return -1;
|
||||
return 0; /* nothing to do, always success */
|
||||
}
|
||||
|
||||
int delete_filter_rule(
|
||||
const char * ifname,
|
||||
unsigned short eport,
|
||||
int proto)
|
||||
{
|
||||
//return -1;
|
||||
return 0; /* nothing to do, always success */
|
||||
}
|
||||
|
||||
int get_redirect_rule_by_index(
|
||||
int index,
|
||||
char * ifname,
|
||||
unsigned short * eport,
|
||||
char * iaddr,
|
||||
int iaddrlen,
|
||||
unsigned short * iport,
|
||||
int * proto,
|
||||
char * desc,
|
||||
int desclen,
|
||||
char * rhost,
|
||||
int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets,
|
||||
u_int64_t * bytes)
|
||||
{
|
||||
int total_rules = 0;
|
||||
struct ip_fw * rules = NULL;
|
||||
|
||||
if (index < 0) // TODO shouldn't we also validate the maximum?
|
||||
return -1;
|
||||
|
||||
if(timestamp)
|
||||
*timestamp = 0;
|
||||
|
||||
ipfw_fetch_ruleset(&rules, &total_rules, index + 1);
|
||||
|
||||
if (total_rules > index) {
|
||||
const struct ip_fw const * ptr = &rules[index];
|
||||
if (ptr->fw_prot == 0) // invalid rule
|
||||
goto error;
|
||||
if (proto != NULL)
|
||||
*proto = ptr->fw_prot;
|
||||
if (eport != NULL)
|
||||
*eport = ptr->fw_uar.fw_pts[0];
|
||||
if (iport != NULL)
|
||||
*iport = ptr->fw_fwd_ip.sin_port;
|
||||
if (ifname != NULL)
|
||||
strlcpy(ifname, ptr->fw_in_if.fu_via_if.name, IFNAMSIZ);
|
||||
if (packets != NULL)
|
||||
*packets = ptr->fw_pcnt;
|
||||
if (bytes != NULL)
|
||||
*bytes = ptr->fw_bcnt;
|
||||
if (iport != NULL)
|
||||
*iport = ptr->fw_fwd_ip.sin_port;
|
||||
if (iaddr != NULL && iaddrlen > 0) {
|
||||
/* looks like fw_out_if.fu_via_ip is zero */
|
||||
//if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
|
||||
if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
|
||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (rhost != NULL && rhostlen > 0) {
|
||||
if (ptr->fw_src.s_addr == 0)
|
||||
rhost[0] = '\0';
|
||||
else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
|
||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
ipfw_free_ruleset(&rules);
|
||||
get_desc_time(*eport, *proto, desc, desclen, timestamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
error:
|
||||
if (rules != NULL)
|
||||
ipfw_free_ruleset(&rules);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* upnp_get_portmappings_in_range()
|
||||
* return a list of all "external" ports for which a port
|
||||
* mapping exists */
|
||||
unsigned short *
|
||||
get_portmappings_in_range(unsigned short startport,
|
||||
unsigned short endport,
|
||||
int proto,
|
||||
unsigned int * number)
|
||||
{
|
||||
unsigned short * array = NULL;
|
||||
unsigned int capacity = 128;
|
||||
int i, count_rules, total_rules = 0;
|
||||
struct ip_fw * rules = NULL;
|
||||
|
||||
if (ipfw_validate_protocol(proto) < 0)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
|
||||
if (count_rules < 0)
|
||||
goto error;
|
||||
} while (count_rules == 10);
|
||||
|
||||
array = calloc(capacity, sizeof(unsigned short));
|
||||
if(!array) {
|
||||
syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
|
||||
goto error;
|
||||
}
|
||||
*number = 0;
|
||||
|
||||
for (i=0; i<total_rules-1; i++) {
|
||||
const struct ip_fw const * ptr = &rules[i];
|
||||
unsigned short eport = ptr->fw_uar.fw_pts[0];
|
||||
if (proto == ptr->fw_prot
|
||||
&& startport <= eport
|
||||
&& eport <= endport) {
|
||||
if(*number >= capacity) {
|
||||
capacity += 128;
|
||||
array = realloc(array, sizeof(unsigned short)*capacity);
|
||||
if(!array) {
|
||||
syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
|
||||
*number = 0;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
array[*number] = eport;
|
||||
(*number)++;
|
||||
}
|
||||
}
|
||||
error:
|
||||
if (rules != NULL)
|
||||
ipfw_free_ruleset(&rules);
|
||||
return array;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/* $Id: ipfwrdr.h,v 1.5 2011/06/04 15:47:18 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009 Jardel Weyrich
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
|
||||
#ifndef __IPFWRDR_H__
|
||||
#define __IPFWRDR_H__
|
||||
|
||||
#include "../commonrdr.h"
|
||||
|
||||
int add_redirect_rule2(
|
||||
const char * ifname, // src interface (external)
|
||||
const char * rhost, // remote host (ip)
|
||||
unsigned short eport, // src port (external)
|
||||
const char * iaddr, // dst address (internal)
|
||||
unsigned short iport, // dst port (internal)
|
||||
int proto,
|
||||
const char * desc,
|
||||
unsigned int timestamp);
|
||||
|
||||
int add_filter_rule2(
|
||||
const char * ifname,
|
||||
const char * rhost,
|
||||
const char * iaddr,
|
||||
unsigned short eport,
|
||||
unsigned short iport,
|
||||
int proto,
|
||||
const char * desc);
|
||||
|
||||
#if 0
|
||||
|
||||
//
|
||||
// get_redirect_rule() gets internal IP and port from
|
||||
// interface, external port and protocl
|
||||
//
|
||||
int get_redirect_rule(
|
||||
const char * ifname,
|
||||
unsigned short eport,
|
||||
int proto,
|
||||
char * iaddr,
|
||||
int iaddrlen,
|
||||
unsigned short * iport,
|
||||
char * desc,
|
||||
int desclen,
|
||||
u_int64_t * packets,
|
||||
u_int64_t * bytes);
|
||||
|
||||
int get_redirect_rule_by_index(
|
||||
int index,
|
||||
char * ifname,
|
||||
unsigned short * eport,
|
||||
char * iaddr,
|
||||
int iaddrlen,
|
||||
unsigned short * iport,
|
||||
int * proto,
|
||||
char * desc,
|
||||
int desclen,
|
||||
u_int64_t * packets,
|
||||
u_int64_t * bytes);
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// delete_redirect_rule()
|
||||
//
|
||||
int delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
//
|
||||
// delete_filter_rule()
|
||||
//
|
||||
int delete_filter_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
int clear_redirect_rules(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
/* $Id: testipfwrdr.c,v 1.7 2011/06/22 21:57:17 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009-2011 Jardel Weyrich, Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include "ipfwrdr.h"
|
||||
|
||||
// test program for ipfwrdr.c
|
||||
static const char * ifname = "lo0";
|
||||
|
||||
static void
|
||||
list_port_mappings(void)
|
||||
{
|
||||
int i;
|
||||
unsigned short eport;
|
||||
char iaddr[16];
|
||||
unsigned short iport;
|
||||
int proto;
|
||||
char desc[64];
|
||||
char rhost[32];
|
||||
unsigned int timestamp;
|
||||
u_int64_t packets, bytes;
|
||||
|
||||
printf("== Port Mapping List ==\n");
|
||||
for(i = 0;; i++) {
|
||||
iaddr[0] = '\0';
|
||||
desc[0] = '\0';
|
||||
eport = iport = 0;
|
||||
timestamp = 0;
|
||||
packets = bytes = 0;
|
||||
proto = -1;
|
||||
if(get_redirect_rule_by_index(i, 0/*ifname*/, &eport, iaddr, sizeof(iaddr),
|
||||
&iport, &proto, desc, sizeof(desc),
|
||||
rhost, sizeof(rhost),
|
||||
×tamp, &packets, &bytes) < 0)
|
||||
break;
|
||||
printf("%2d - %5hu=>%15s:%5hu %d '%s' '%s' %u %" PRIu64 " %" PRIu64 "\n",
|
||||
i, eport, iaddr, iport, proto, desc, rhost, timestamp,
|
||||
packets, bytes);
|
||||
}
|
||||
printf("== %d Port Mapping%s ==\n", i, (i > 1)?"s":"");
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv) {
|
||||
unsigned int timestamp;
|
||||
char desc[64];
|
||||
char addr[16];
|
||||
char rhost[40];
|
||||
unsigned short iport = 0;
|
||||
const char * in_rhost = "8.8.8.8";
|
||||
|
||||
desc[0] = '\0';
|
||||
addr[0] = '\0';
|
||||
openlog("testipfwrdrd", LOG_CONS | LOG_PERROR, LOG_USER);
|
||||
if(init_redirect() < 0) {
|
||||
fprintf(stderr, "init_redirect() failed.\n");
|
||||
return 1;
|
||||
}
|
||||
list_port_mappings();
|
||||
delete_redirect_rule(ifname, 2222, IPPROTO_TCP);
|
||||
delete_redirect_rule(ifname, 2223, IPPROTO_TCP);
|
||||
add_redirect_rule2(ifname, "", 2223,
|
||||
"10.1.1.17", 4445, IPPROTO_TCP,
|
||||
"test miniupnpd", time(NULL) + 60);
|
||||
add_redirect_rule2(ifname, in_rhost, 2222,
|
||||
"10.1.1.16", 4444, IPPROTO_TCP,
|
||||
"test miniupnpd", time(NULL) + 60);
|
||||
get_redirect_rule(ifname, 2222, IPPROTO_TCP, addr, sizeof(addr), &iport,
|
||||
desc, sizeof(desc), rhost, sizeof(rhost),
|
||||
×tamp, NULL, NULL);
|
||||
printf("'%s' %s:%hu '%s' %u\n", rhost, addr, iport, desc, timestamp);
|
||||
list_port_mappings();
|
||||
delete_redirect_rule(ifname, 2222, IPPROTO_TCP);
|
||||
delete_redirect_rule(ifname, 2223, IPPROTO_TCP);
|
||||
list_port_mappings();
|
||||
shutdown_redirect();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/* $Id: getifstats.c,v 1.9 2011/05/25 22:22:57 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../getifstats.h"
|
||||
|
||||
int
|
||||
getifstats(const char * ifname, struct ifdata * data)
|
||||
{
|
||||
FILE *f;
|
||||
char line[512];
|
||||
char * p;
|
||||
int i;
|
||||
int r = -1;
|
||||
char fname[64];
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
static time_t cache_timestamp = 0;
|
||||
static struct ifdata cache_data;
|
||||
time_t current_time;
|
||||
#endif
|
||||
if(!data)
|
||||
return -1;
|
||||
data->baudrate = 4200000; /* that is the answer */
|
||||
data->opackets = 0;
|
||||
data->ipackets = 0;
|
||||
data->obytes = 0;
|
||||
data->ibytes = 0;
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
current_time = time(NULL);
|
||||
if(current_time == ((time_t)-1)) {
|
||||
syslog(LOG_ERR, "getifstats() : time() error : %m");
|
||||
} else {
|
||||
if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
|
||||
/* return cached data */
|
||||
memcpy(data, &cache_data, sizeof(struct ifdata));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
f = fopen("/proc/net/dev", "r");
|
||||
if(!f) {
|
||||
syslog(LOG_ERR, "getifstats() : cannot open /proc/net/dev : %m");
|
||||
return -1;
|
||||
}
|
||||
/* discard the two header lines */
|
||||
if(!fgets(line, sizeof(line), f) || !fgets(line, sizeof(line), f)) {
|
||||
syslog(LOG_ERR, "getifstats() : error reading /proc/net/dev : %m");
|
||||
}
|
||||
while(fgets(line, sizeof(line), f)) {
|
||||
p = line;
|
||||
while(*p==' ') p++;
|
||||
i = 0;
|
||||
while(ifname[i] == *p) {
|
||||
p++; i++;
|
||||
}
|
||||
/* TODO : how to handle aliases ? */
|
||||
if(ifname[i] || *p != ':')
|
||||
continue;
|
||||
p++;
|
||||
while(*p==' ') p++;
|
||||
data->ibytes = strtoul(p, &p, 0);
|
||||
while(*p==' ') p++;
|
||||
data->ipackets = strtoul(p, &p, 0);
|
||||
/* skip 6 columns */
|
||||
for(i=6; i>0 && *p!='\0'; i--) {
|
||||
while(*p==' ') p++;
|
||||
while(*p!=' ' && *p) p++;
|
||||
}
|
||||
while(*p==' ') p++;
|
||||
data->obytes = strtoul(p, &p, 0);
|
||||
while(*p==' ') p++;
|
||||
data->opackets = strtoul(p, &p, 0);
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
/* get interface speed */
|
||||
snprintf(fname, sizeof(fname), "/sys/class/net/%s/speed", ifname);
|
||||
f = fopen(fname, "r");
|
||||
if(f) {
|
||||
if(fgets(line, sizeof(line), f)) {
|
||||
data->baudrate = 1000000*atoi(line);
|
||||
}
|
||||
fclose(f);
|
||||
} else {
|
||||
syslog(LOG_WARNING, "cannot read %s file : %m", fname);
|
||||
}
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
if(r==0 && current_time!=((time_t)-1)) {
|
||||
/* cache the new data */
|
||||
cache_timestamp = current_time;
|
||||
memcpy(&cache_data, data, sizeof(struct ifdata));
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
/* $Id: ifacewatcher.c,v 1.2 2011/07/30 13:11:39 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2009 Thomas Bernard
|
||||
*
|
||||
* ifacewatcher.c
|
||||
*
|
||||
* This file implements dynamic serving of new network interfaces
|
||||
* which weren't available during daemon start. It also takes care
|
||||
* of interfaces which become unavailable.
|
||||
*
|
||||
* Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
|
||||
* 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. */
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifdef USE_IFACEWATCHER
|
||||
|
||||
#include "../ifacewatcher.h"
|
||||
#include "../minissdp.h"
|
||||
#include "../getifaddr.h"
|
||||
#include "../upnpglobalvars.h"
|
||||
#include "../natpmp.h"
|
||||
|
||||
extern volatile int should_send_public_address_change_notif;
|
||||
|
||||
|
||||
int
|
||||
OpenAndConfInterfaceWatchSocket(void)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (s == -1)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
|
||||
/*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;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* disabled at the moment */
|
||||
int
|
||||
ProcessInterfaceUp(struct ifinfomsg *ifi)
|
||||
{
|
||||
struct lan_iface_s * lan_iface;
|
||||
struct lan_iface_s * lan_iface2;
|
||||
struct lan_addr_s * lan_addr;
|
||||
char ifname[IFNAMSIZ];
|
||||
char ifstraddr[16];
|
||||
struct in_addr ifaddr;
|
||||
|
||||
/* check if we already have this iface */
|
||||
for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
|
||||
if (lan_iface->iface.index == ifi->ifi_index)
|
||||
break;
|
||||
|
||||
if (lan_iface != NULL)
|
||||
return 0;
|
||||
|
||||
if (if_indextoname(ifi->ifi_index, ifname) == NULL)
|
||||
{
|
||||
syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (getifaddr(ifname, ifstraddr, 16) < 0)
|
||||
{
|
||||
syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
|
||||
{
|
||||
syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check if this new interface has address which we need to listen to */
|
||||
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
|
||||
{
|
||||
if (lan_addr->addr.s_addr != ifaddr.s_addr)
|
||||
continue;
|
||||
|
||||
syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
|
||||
|
||||
/* adding new lan_iface entry */
|
||||
lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
|
||||
if (lan_iface == NULL)
|
||||
{
|
||||
syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
lan_iface->lan_addr = lan_addr;
|
||||
strncpy(lan_iface->iface.name, ifname, IFNAMSIZ);
|
||||
lan_iface->iface.index = ifi->ifi_index;
|
||||
lan_iface->iface.addr = ifaddr;
|
||||
lan_iface->snotify = -1;
|
||||
#ifdef ENABLE_NATPMP
|
||||
lan_iface->snatpmp = -1;
|
||||
#endif
|
||||
|
||||
LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
|
||||
|
||||
/* adding multicast membership for SSDP */
|
||||
if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0)
|
||||
syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr);
|
||||
else
|
||||
syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr);
|
||||
|
||||
/* create SSDP notify socket */
|
||||
if (OpenAndConfSSDPNotifySocket(lan_iface) < 0)
|
||||
syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr);
|
||||
|
||||
#ifdef ENABLE_NATPMP
|
||||
/* create NAT-PMP socket */
|
||||
for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
|
||||
if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr &&
|
||||
lan_iface2->snatpmp >= 0)
|
||||
lan_iface->snatpmp = lan_iface2->snatpmp;
|
||||
|
||||
if (lan_iface->snatpmp < 0)
|
||||
{
|
||||
lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr);
|
||||
if (lan_iface->snatpmp < 0)
|
||||
syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr);
|
||||
else
|
||||
syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ProcessInterfaceDown(struct ifinfomsg *ifi)
|
||||
{
|
||||
struct lan_iface_s * lan_iface;
|
||||
struct lan_iface_s * lan_iface2;
|
||||
|
||||
/* check if we have this iface */
|
||||
for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
|
||||
if (lan_iface->iface.index == ifi->ifi_index)
|
||||
break;
|
||||
|
||||
if (lan_iface == NULL)
|
||||
return 0;
|
||||
|
||||
/* one of our interfaces is going down, clean up */
|
||||
syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
|
||||
|
||||
/* remove multicast membership for SSDP */
|
||||
if(DropMulticastMembership(sudp, lan_iface->lan_addr->addr.s_addr, lan_iface->iface.index) < 0)
|
||||
syslog(LOG_WARNING, "Failed to drop multicast membership for interface %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
|
||||
else
|
||||
syslog(LOG_INFO, "Multicast membership dropped for %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
|
||||
|
||||
/* closing SSDP notify socket */
|
||||
close(lan_iface->snotify);
|
||||
|
||||
#ifdef ENABLE_NATPMP
|
||||
/* closing NAT-PMP socket if it's not used anymore */
|
||||
for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
|
||||
if (lan_iface2 != lan_iface && lan_iface2->snatpmp == lan_iface->snatpmp)
|
||||
break;
|
||||
|
||||
if (lan_iface2 == NULL)
|
||||
close(lan_iface->snatpmp);
|
||||
#endif
|
||||
|
||||
/* del corresponding lan_iface entry */
|
||||
LIST_REMOVE(lan_iface, list);
|
||||
free(lan_iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ProcessInterfaceWatchNotify(int s)
|
||||
{
|
||||
char buffer[4096];
|
||||
struct iovec iov;
|
||||
struct msghdr hdr;
|
||||
struct nlmsghdr *nlhdr;
|
||||
struct ifinfomsg *ifi;
|
||||
struct ifaddrmsg *ifa;
|
||||
int len;
|
||||
|
||||
struct rtattr *rth; //
|
||||
int rtl;
|
||||
|
||||
unsigned int ext_if_name_index = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(ext_if_name) {
|
||||
ext_if_name_index = if_nametoindex(ext_if_name);
|
||||
}
|
||||
|
||||
for (nlhdr = (struct nlmsghdr *) buffer;
|
||||
NLMSG_OK (nlhdr, len);
|
||||
nlhdr = NLMSG_NEXT (nlhdr, len))
|
||||
{
|
||||
if (nlhdr->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
switch(nlhdr->nlmsg_type) {
|
||||
case RTM_DELLINK:
|
||||
ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
|
||||
/*if (ProcessInterfaceDown(ifi) < 0)
|
||||
syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");*/
|
||||
break;
|
||||
case RTM_NEWLINK:
|
||||
ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
|
||||
/*if (ProcessInterfaceUp(ifi) < 0)
|
||||
syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");*/
|
||||
break;
|
||||
case RTM_NEWADDR:
|
||||
/* see /usr/include/linux/netlink.h
|
||||
* and /usr/include/linux/rtnetlink.h */
|
||||
ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
|
||||
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR");
|
||||
for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
|
||||
rtl && RTA_OK(rth, rtl);
|
||||
rth = RTA_NEXT(rth, rtl)) {
|
||||
syslog(LOG_DEBUG, " - %u - %s type=%d",
|
||||
ifa->ifa_index, inet_ntoa(*((struct in_addr *)RTA_DATA(rth))),
|
||||
rth->rta_type);
|
||||
}
|
||||
if(ifa->ifa_index == ext_if_name_index) {
|
||||
should_send_public_address_change_notif = 1;
|
||||
}
|
||||
break;
|
||||
case RTM_DELADDR:
|
||||
ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
|
||||
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR");
|
||||
if(ifa->ifa_index == ext_if_name_index) {
|
||||
should_send_public_address_change_notif = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify type %d ignored", nlhdr->nlmsg_type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/sh
|
||||
# $Id: miniupnpd.init.d.script,v 1.2 2007/09/23 16:11:12 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# author: Thomas Bernard
|
||||
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
||||
MINIUPNPD=/usr/sbin/miniupnpd
|
||||
ARGS='-f /etc/miniupnpd/miniupnpd.conf'
|
||||
|
||||
IPTABLES_CREATE=/etc/miniupnpd/iptables_init.sh
|
||||
IPTABLES_REMOVE=/etc/miniupnpd/iptables_removeall.sh
|
||||
|
||||
test -f $MINIUPNPD || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
case "$1" in
|
||||
start) log_daemon_msg "Starting miniupnpd" "miniupnpd"
|
||||
$IPTABLES_CREATE > /dev/null 2>&1
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/miniupnpd.pid --startas $MINIUPNPD -- $ARGS $LSBNAMES
|
||||
log_end_msg $?
|
||||
;;
|
||||
stop) log_daemon_msg "Stopping miniupnpd" "miniupnpd"
|
||||
start-stop-daemon --stop --quiet --pidfile /var/run/miniupnpd.pid
|
||||
log_end_msg $?
|
||||
$IPTABLES_REMOVE > /dev/null 2>&1
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
log_daemon_msg "Restarting miniupnpd" "miniupnpd"
|
||||
start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/miniupnpd.pid
|
||||
$IPTABLES_REMOVE > /dev/null 2>&1
|
||||
$IPTABLES_CREATE > /dev/null 2>&1
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/miniupnpd.pid --startas $MINIUPNPD -- $ARGS $LSBNAMES
|
||||
log_end_msg $?
|
||||
;;
|
||||
*) log_action_msg "Usage: /etc/init.d/miniupnpd {start|stop|restart|reload|force-reload}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
exit 0
|
|
@ -0,0 +1,14 @@
|
|||
# $Id: Makefile,v 1.2 2011/02/20 23:43:41 nanard Exp $
|
||||
# made for GNU Make
|
||||
CFLAGS = -Wall -g
|
||||
EXECUTABLES = testgetifstats
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXECUTABLES)
|
||||
|
||||
testmacrdr.o: testmacrdr.c macrdr.h
|
||||
|
||||
testgetifstats: testgetifstats.o getifstats.o
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/* $Id: getifstats.c,v 1.5 2011/07/03 22:22:04 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009 Jardel Weyrich
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
|
||||
#include <syslog.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <nlist.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../getifstats.h"
|
||||
#include "../config.h"
|
||||
|
||||
int getifstats(const char * ifname, struct ifdata * data) {
|
||||
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(ifname) };
|
||||
const size_t mib_len = sizeof(mib) / sizeof(mib[0]);
|
||||
size_t needed;
|
||||
char *buf, *end, *p;
|
||||
struct if_msghdr *ifm;
|
||||
struct if_data ifdata;
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
static time_t cache_timestamp = 0;
|
||||
static struct ifdata cache_data;
|
||||
time_t current_time;
|
||||
#endif
|
||||
|
||||
if (data == NULL || ifname == NULL || ifname[0] == '\0')
|
||||
return -1; // error
|
||||
|
||||
data->baudrate = 4200000;
|
||||
data->opackets = 0;
|
||||
data->ipackets = 0;
|
||||
data->obytes = 0;
|
||||
data->ibytes = 0;
|
||||
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
current_time = time(NULL);
|
||||
if (current_time == ((time_t)-1)) {
|
||||
syslog(LOG_ERR, "getifstats() : time() error : %m");
|
||||
} else {
|
||||
if (current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
|
||||
memcpy(data, &cache_data, sizeof(struct ifdata));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sysctl(mib, mib_len, NULL, &needed, NULL, 0) == -1) {
|
||||
syslog(LOG_ERR, "sysctl(): %m");
|
||||
return -1;
|
||||
}
|
||||
buf = (char *) malloc(needed);
|
||||
if (buf == NULL)
|
||||
return -1; // error
|
||||
if (sysctl(mib, mib_len, buf, &needed, NULL, 0) == -1) {
|
||||
syslog(LOG_ERR, "sysctl(): %m");
|
||||
free(buf);
|
||||
return -1; // error
|
||||
} else {
|
||||
for (end = buf + needed, p = buf; p < end; p += ifm->ifm_msglen) {
|
||||
ifm = (struct if_msghdr *) p;
|
||||
if (ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER) {
|
||||
ifdata = ifm->ifm_data;
|
||||
data->opackets = ifdata.ifi_opackets;
|
||||
data->ipackets = ifdata.ifi_ipackets;
|
||||
data->obytes = ifdata.ifi_obytes;
|
||||
data->ibytes = ifdata.ifi_ibytes;
|
||||
data->baudrate = ifdata.ifi_baudrate;
|
||||
free(buf);
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
if (current_time!=((time_t)-1)) {
|
||||
cache_timestamp = current_time;
|
||||
memcpy(&cache_data, data, sizeof(struct ifdata));
|
||||
}
|
||||
#endif
|
||||
return 0; // found, ok
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return -1; // not found or error
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>miniupnpd</key>
|
||||
<string>org.tuxfamily.miniupnpd</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/sbin/miniupnpd</string>
|
||||
<string>-f /etc/miniupnpd/miniupnpd.conf</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,29 @@
|
|||
/* $Id: testgetifstats.c,v 1.3 2011/02/20 23:43:41 nanard Exp $ */
|
||||
/*
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2009 Jardel Weyrich
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../getifstats.h"
|
||||
|
||||
int main(int argc, char * * argv) {
|
||||
int r;
|
||||
struct ifdata data;
|
||||
printf("usage: %s if_name\n", argv[0]);
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
r = getifstats(argv[1], &data);
|
||||
if (r < 0)
|
||||
printf("getifstats() failed\n");
|
||||
else {
|
||||
printf("ipackets = %10lu opackets = %10lu\n", data.ipackets, data.opackets);
|
||||
printf("ibytes = %10lu obytes = %10lu\n", data.ibytes, data.obytes);
|
||||
printf("baudrate = %10lu\n", data.baudrate);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,635 @@
|
|||
/* $Id: minissdp.c,v 1.27 2011/05/23 12:39:41 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include "config.h"
|
||||
#include "upnpdescstrings.h"
|
||||
#include "miniupnpdpath.h"
|
||||
#include "upnphttp.h"
|
||||
#include "upnpglobalvars.h"
|
||||
#include "minissdp.h"
|
||||
#include "upnputils.h"
|
||||
#include "codelength.h"
|
||||
|
||||
/* SSDP ip/port */
|
||||
#define SSDP_PORT (1900)
|
||||
#define SSDP_MCAST_ADDR ("239.255.255.250")
|
||||
#define LL_SSDP_MCAST_ADDR ("FF02::C")
|
||||
#define SL_SSDP_MCAST_ADDR ("FF05::C")
|
||||
|
||||
/* AddMulticastMembership()
|
||||
* param s socket
|
||||
* param ifaddr ip v4 address
|
||||
*/
|
||||
static int
|
||||
AddMulticastMembership(int s, in_addr_t ifaddr)
|
||||
{
|
||||
struct ip_mreq imr; /* Ip multicast membership */
|
||||
|
||||
/* 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 = ifaddr; /*inet_addr(ifaddr);*/
|
||||
|
||||
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AddMulticastMembershipIPv6()
|
||||
* param s socket (IPv6)
|
||||
* To be improved to target specific network interfaces */
|
||||
#ifdef ENABLE_IPV6
|
||||
static int
|
||||
AddMulticastMembershipIPv6(int s)
|
||||
{
|
||||
struct ipv6_mreq mr;
|
||||
/*unsigned int ifindex;*/
|
||||
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||
/*mr.ipv6mr_interface = ifindex;*/
|
||||
mr.ipv6mr_interface = 0; /* 0 : all interfaces */
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
|
||||
return -1;
|
||||
}
|
||||
inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open and configure the socket listening for
|
||||
* SSDP udp packets sent on 239.255.255.250 port 1900
|
||||
* SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
|
||||
int
|
||||
OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_storage sockname;
|
||||
socklen_t sockname_len;
|
||||
struct lan_addr_s * lan_addr;
|
||||
int j = 1;
|
||||
|
||||
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(udp): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_storage));
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
|
||||
saddr->sin6_family = AF_INET6;
|
||||
saddr->sin6_port = htons(SSDP_PORT);
|
||||
saddr->sin6_addr = in6addr_any;
|
||||
sockname_len = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
|
||||
saddr->sin_family = AF_INET;
|
||||
saddr->sin_port = htons(SSDP_PORT);
|
||||
/* NOTE : it seems it doesnt work when binding on the specific address */
|
||||
/*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
|
||||
saddr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
/*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
|
||||
sockname_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
|
||||
}
|
||||
|
||||
|
||||
if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6)
|
||||
{
|
||||
AddMulticastMembershipIPv6(s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
|
||||
{
|
||||
if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"Failed to add multicast membership for interface %s",
|
||||
lan_addr->str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* open the UDP socket used to send SSDP notifications to
|
||||
* the multicast group reserved for them */
|
||||
static int
|
||||
OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
||||
{
|
||||
int s;
|
||||
unsigned char loopchar = 0;
|
||||
int bcast = 1;
|
||||
struct in_addr mc_if;
|
||||
struct sockaddr_in sockname;
|
||||
|
||||
if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(udp_notify): %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mc_if.s_addr = addr; /*inet_addr(addr);*/
|
||||
|
||||
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp_notify, SO_BROADCAST): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_addr.s_addr = addr; /*inet_addr(addr);*/
|
||||
|
||||
if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "bind(udp_notify): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
OpenAndConfSSDPNotifySockets(int * sockets)
|
||||
/*OpenAndConfSSDPNotifySockets(int * sockets,
|
||||
struct lan_addr_s * lan_addr, int n_lan_addr)*/
|
||||
{
|
||||
int i, j;
|
||||
struct lan_addr_s * lan_addr;
|
||||
|
||||
for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
|
||||
{
|
||||
sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr);
|
||||
if(sockets[i] < 0)
|
||||
{
|
||||
for(j=0; j<i; j++)
|
||||
{
|
||||
close(sockets[j]);
|
||||
sockets[j] = -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* response from a LiveBox (Wanadoo)
|
||||
HTTP/1.1 200 OK
|
||||
CACHE-CONTROL: max-age=1800
|
||||
DATE: Thu, 01 Jan 1970 04:03:23 GMT
|
||||
EXT:
|
||||
LOCATION: http://192.168.0.1:49152/gatedesc.xml
|
||||
SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
|
||||
ST: upnp:rootdevice
|
||||
USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
|
||||
|
||||
* response from a Linksys 802.11b :
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control:max-age=120
|
||||
Location:http://192.168.5.1:5678/rootDesc.xml
|
||||
Server:NT/5.0 UPnP/1.0
|
||||
ST:upnp:rootdevice
|
||||
USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
|
||||
EXT:
|
||||
*/
|
||||
|
||||
/* not really an SSDP "announce" as it is the response
|
||||
* to a SSDP "M-SEARCH" */
|
||||
static void
|
||||
SendSSDPAnnounce2(int s, const struct sockaddr * addr,
|
||||
const char * st, int st_len, const char * suffix,
|
||||
const char * host, unsigned short port)
|
||||
{
|
||||
int l, n;
|
||||
char buf[512];
|
||||
socklen_t addrlen;
|
||||
/*
|
||||
* follow guideline from document "UPnP Device Architecture 1.0"
|
||||
* uppercase is recommended.
|
||||
* DATE: is recommended
|
||||
* SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
|
||||
* - check what to put in the 'Cache-Control' header
|
||||
*
|
||||
* have a look at the document "UPnP Device Architecture v1.1 */
|
||||
l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=120\r\n"
|
||||
/*"DATE: ...\r\n"*/
|
||||
"ST: %.*s%s\r\n"
|
||||
"USN: %s::%.*s%s\r\n"
|
||||
"EXT:\r\n"
|
||||
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
|
||||
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
|
||||
"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
|
||||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"\r\n",
|
||||
st_len, st, suffix,
|
||||
uuidvalue, st_len, st, suffix,
|
||||
host, (unsigned int)port,
|
||||
upnp_bootid, upnp_bootid, upnp_configid);
|
||||
addrlen = (addr->sa_family == AF_INET6)
|
||||
? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
||||
n = sendto(s, buf, l, 0,
|
||||
addr, addrlen);
|
||||
syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n,
|
||||
inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
|
||||
ntohs(((const struct sockaddr_in *)addr)->sin_port),
|
||||
l, buf);
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "sendto(udp): %m");
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const known_service_types[] =
|
||||
{
|
||||
"upnp:rootdevice",
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:",
|
||||
"urn:schemas-upnp-org:device:WANConnectionDevice:",
|
||||
"urn:schemas-upnp-org:device:WANDevice:",
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:",
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
"urn:schemas-upnp-org:service:Layer3Forwarding:",
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
"url:schemas-upnp-org:service:WANIPv6FirewallControl:",
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
static void
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short port,
|
||||
unsigned int lifetime)
|
||||
{
|
||||
struct sockaddr_in sockname;
|
||||
int l, n, i=0;
|
||||
char bufr[512];
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_port = htons(SSDP_PORT);
|
||||
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
|
||||
while(known_service_types[i])
|
||||
{
|
||||
l = snprintf(bufr, sizeof(bufr),
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
"HOST: %s:%d\r\n"
|
||||
"CACHE-CONTROL: max-age=%u\r\n"
|
||||
"lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
|
||||
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
|
||||
"NT: %s%s\r\n"
|
||||
"USN: %s::%s%s\r\n"
|
||||
"NTS: ssdp:alive\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
|
||||
"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
|
||||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"\r\n",
|
||||
SSDP_MCAST_ADDR, SSDP_PORT,
|
||||
lifetime,
|
||||
host, port,
|
||||
known_service_types[i], (i==0?"":"1"),
|
||||
uuidvalue, known_service_types[i], (i==0?"":"1"),
|
||||
upnp_bootid, upnp_bootid, upnp_configid );
|
||||
if(l>=sizeof(bufr))
|
||||
{
|
||||
syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output");
|
||||
l = sizeof(bufr);
|
||||
}
|
||||
n = sendto(s, bufr, l, 0,
|
||||
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SendSSDPNotifies2(int * sockets,
|
||||
unsigned short port,
|
||||
unsigned int lifetime)
|
||||
{
|
||||
int i;
|
||||
struct lan_addr_s * lan_addr;
|
||||
for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
|
||||
{
|
||||
SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
/* ProcessSSDPRequest()
|
||||
* process SSDP M-SEARCH requests and responds to them */
|
||||
void
|
||||
ProcessSSDPRequest(int s, unsigned short port)
|
||||
{
|
||||
int n;
|
||||
char bufr[1500];
|
||||
socklen_t len_r;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_storage sendername;
|
||||
len_r = sizeof(struct sockaddr_storage);
|
||||
#else
|
||||
struct sockaddr_in sendername;
|
||||
len_r = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
n = recvfrom(s, bufr, sizeof(bufr), 0,
|
||||
(struct sockaddr *)&sendername, &len_r);
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "recvfrom(udp): %m");
|
||||
return;
|
||||
}
|
||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sender, unsigned short port) {
|
||||
int i, l;
|
||||
struct lan_addr_s * lan_addr = NULL;
|
||||
const char * st = NULL;
|
||||
int st_len = 0;
|
||||
char sender_str[64];
|
||||
const char * announced_host = NULL;
|
||||
|
||||
/* get the string representation of the sender address */
|
||||
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
||||
|
||||
if(memcmp(bufr, "NOTIFY", 6) == 0)
|
||||
{
|
||||
/* ignore NOTIFY packets. We could log the sender and device type */
|
||||
return;
|
||||
}
|
||||
else if(memcmp(bufr, "M-SEARCH", 8) == 0)
|
||||
{
|
||||
i = 0;
|
||||
while(i < n)
|
||||
{
|
||||
while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
|
||||
i++;
|
||||
i += 2;
|
||||
if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
|
||||
{
|
||||
st = bufr+i+3;
|
||||
st_len = 0;
|
||||
while((*st == ' ' || *st == '\t') && (st < bufr + n))
|
||||
st++;
|
||||
while(st[st_len]!='\r' && st[st_len]!='\n'
|
||||
&& (st + st_len < bufr + n))
|
||||
st_len++;
|
||||
/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
|
||||
/*j = 0;*/
|
||||
/*while(bufr[i+j]!='\r') j++;*/
|
||||
/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
|
||||
}
|
||||
}
|
||||
/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
|
||||
sender_str );*/
|
||||
if(st && (st_len > 0))
|
||||
{
|
||||
/* TODO : doesnt answer at once but wait for a random time */
|
||||
syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
|
||||
sender_str, st_len, st);
|
||||
/* find in which sub network the client is */
|
||||
if(sender->sa_family == AF_INET)
|
||||
{
|
||||
for(lan_addr = lan_addrs.lh_first;
|
||||
lan_addr != NULL;
|
||||
lan_addr = lan_addr->list.le_next)
|
||||
{
|
||||
if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
|
||||
== (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
|
||||
break;
|
||||
}
|
||||
if (lan_addr == NULL)
|
||||
{
|
||||
syslog(LOG_ERR, "Can't find in which sub network the client is");
|
||||
return;
|
||||
}
|
||||
announced_host = lan_addr->str;
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
else
|
||||
{
|
||||
/* IPv6 address with brackets */
|
||||
announced_host = ipv6_addr_for_http_with_brackets;
|
||||
}
|
||||
#endif
|
||||
/* Responds to request with a device as ST header */
|
||||
for(i = 0; known_service_types[i]; i++)
|
||||
{
|
||||
l = (int)strlen(known_service_types[i]);
|
||||
if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
|
||||
{
|
||||
syslog(LOG_INFO, "Single search found");
|
||||
SendSSDPAnnounce2(s, sender,
|
||||
st, st_len, "",
|
||||
announced_host, port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Responds to request with ST: ssdp:all */
|
||||
/* strlen("ssdp:all") == 8 */
|
||||
if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
|
||||
{
|
||||
syslog(LOG_INFO, "ssdp:all found");
|
||||
for(i=0; known_service_types[i]; i++)
|
||||
{
|
||||
l = (int)strlen(known_service_types[i]);
|
||||
SendSSDPAnnounce2(s, sender,
|
||||
known_service_types[i], l, i==0?"":"1",
|
||||
announced_host, port);
|
||||
}
|
||||
}
|
||||
/* responds to request by UUID value */
|
||||
l = (int)strlen(uuidvalue);
|
||||
if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
|
||||
{
|
||||
syslog(LOG_INFO, "ssdp:uuid found");
|
||||
SendSSDPAnnounce2(s, sender, st, st_len, "",
|
||||
announced_host, port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* This will broadcast ssdp:byebye notifications to inform
|
||||
* the network that UPnP is going down. */
|
||||
int
|
||||
SendSSDPGoodbye(int * sockets, int n_sockets)
|
||||
{
|
||||
struct sockaddr_in sockname;
|
||||
int n, l;
|
||||
int i, j;
|
||||
char bufr[512];
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_port = htons(SSDP_PORT);
|
||||
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
|
||||
for(j=0; j<n_sockets; j++)
|
||||
{
|
||||
for(i=0; known_service_types[i]; i++)
|
||||
{
|
||||
l = snprintf(bufr, sizeof(bufr),
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
"HOST: %s:%d\r\n"
|
||||
"NT: %s%s\r\n"
|
||||
"USN: %s::%s%s\r\n"
|
||||
"NTS: ssdp:byebye\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */
|
||||
"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
|
||||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"\r\n",
|
||||
SSDP_MCAST_ADDR, SSDP_PORT,
|
||||
known_service_types[i], (i==0?"":"1"),
|
||||
uuidvalue, known_service_types[i], (i==0?"":"1"),
|
||||
upnp_bootid, upnp_bootid, upnp_configid);
|
||||
n = sendto(sockets[j], bufr, l, 0,
|
||||
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "SendSSDPGoodbye: sendto(udp_shutdown=%d): %m",
|
||||
sockets[j]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SubmitServicesToMiniSSDPD() :
|
||||
* register services offered by MiniUPnPd to a running instance of
|
||||
* MiniSSDPd */
|
||||
int
|
||||
SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
|
||||
struct sockaddr_un addr;
|
||||
int s;
|
||||
unsigned char buffer[2048];
|
||||
char strbuf[256];
|
||||
unsigned char * p;
|
||||
int i, l;
|
||||
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s < 0) {
|
||||
syslog(LOG_ERR, "socket(unix): %m");
|
||||
return -1;
|
||||
}
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
|
||||
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
|
||||
syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath);
|
||||
return -1;
|
||||
}
|
||||
for(i = 0; known_service_types[i]; i++) {
|
||||
buffer[0] = 4;
|
||||
p = buffer + 1;
|
||||
l = (int)strlen(known_service_types[i]);
|
||||
if(i > 0)
|
||||
l++;
|
||||
CODELENGTH(l, p);
|
||||
memcpy(p, known_service_types[i], l);
|
||||
if(i > 0)
|
||||
p[l-1] = '1';
|
||||
p += l;
|
||||
l = snprintf(strbuf, sizeof(strbuf), "%s::%s%s",
|
||||
uuidvalue, known_service_types[i], (i==0)?"":"1");
|
||||
CODELENGTH(l, p);
|
||||
memcpy(p, strbuf, l);
|
||||
p += l;
|
||||
l = (int)strlen(MINIUPNPD_SERVER_STRING);
|
||||
CODELENGTH(l, p);
|
||||
memcpy(p, MINIUPNPD_SERVER_STRING, l);
|
||||
p += l;
|
||||
l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,
|
||||
host, (unsigned int)port);
|
||||
CODELENGTH(l, p);
|
||||
memcpy(p, strbuf, l);
|
||||
p += l;
|
||||
if(write(s, buffer, p - buffer) < 0) {
|
||||
syslog(LOG_ERR, "write(): %m");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/* $Id: minissdp.h,v 1.10 2011/05/23 12:39:41 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2007 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef __MINISSDP_H__
|
||||
#define __MINISSDP_H__
|
||||
|
||||
#include "miniupnpdtypes.h"
|
||||
|
||||
int
|
||||
OpenAndConfSSDPReceiveSocket(int ipv6);
|
||||
|
||||
int
|
||||
OpenAndConfSSDPNotifySockets(int * sockets);
|
||||
/*OpenAndConfSSDPNotifySockets(int * sockets,
|
||||
struct lan_addr_s * lan_addr, int n_lan_addr);*/
|
||||
|
||||
/*void
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short port,
|
||||
unsigned int lifetime);*/
|
||||
void
|
||||
SendSSDPNotifies2(int * sockets,
|
||||
unsigned short port,
|
||||
unsigned int lifetime);
|
||||
/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,
|
||||
unsigned short port,
|
||||
unsigned int lifetime);*/
|
||||
|
||||
void
|
||||
ProcessSSDPRequest(int s, unsigned short port);
|
||||
/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr,
|
||||
unsigned short port);*/
|
||||
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sendername, unsigned short port);
|
||||
|
||||
int
|
||||
SendSSDPGoodbye(int * sockets, int n);
|
||||
|
||||
int
|
||||
SubmitServicesToMiniSSDPD(const char * host, unsigned short port);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
.TH miniupnpd 1
|
||||
.SH NAME
|
||||
miniupnpd \- UPnP Internet Gateway Device Daemon
|
||||
.SH SYNOPSIS
|
||||
.B miniupnpd
|
||||
[-f file] [-i interface] [-o address]
|
||||
[-a address] [-p port] [-d] [-L] [-U]
|
||||
[-u uuid] [-s serial] [-m model_number]
|
||||
[-q queue]
|
||||
[-t interval] [-P file]
|
||||
[-B down up] [-w url]
|
||||
.SH DESCRIPTION
|
||||
miniupnpd act as a UPnP Internet Gateway Device. It is designed
|
||||
to run on the gateway between the internet and a NAT'ed LAN. It provides
|
||||
an interface, as defined in the UPnP standard, for enabling
|
||||
clients on the LAN to ask for port redirections.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-f file
|
||||
load the config from file. default is /etc/miniupnpd.conf.
|
||||
.TP
|
||||
.B \-i interface
|
||||
interface used to connect to the internet.
|
||||
.TP
|
||||
.B \-o address
|
||||
address used to connect to the internet.
|
||||
default address of the interface will be used if not specified.
|
||||
.TP
|
||||
.B \-a address
|
||||
address on the LAN. -a option can by used multiple time if LAN is
|
||||
subdivised in several subnetworks.
|
||||
.TP
|
||||
.B \-p port
|
||||
port used for HTTP.
|
||||
.TP
|
||||
.B \-d
|
||||
debug mode : do not go to background, output messages on console
|
||||
and do not filter out low priority messages.
|
||||
.TP
|
||||
.B \-L
|
||||
set packet log in pf on
|
||||
.TP
|
||||
.B \-q queue
|
||||
set ALTQ queue in pf. filter rules must be enabled for this option
|
||||
to have any effect.
|
||||
.TP
|
||||
.B \-U
|
||||
report system uptime instead of daemon uptime to clients.
|
||||
.TP
|
||||
.B \-u uuid
|
||||
set the uuid of the UPnP Internet Gateway Device.
|
||||
.TP
|
||||
.B \-s serial
|
||||
serial number for the UPnP Internet Gateway Device.
|
||||
.TP
|
||||
.B \-m number
|
||||
model number for the UPnP Internet Gateway Device.
|
||||
.TP
|
||||
.B \-t interval
|
||||
SSDP notify interval in seconds :
|
||||
SSDP announce messages will be broadcasted at this interval.
|
||||
.TP
|
||||
.B \-P file
|
||||
pid file. default is /var/run/miniupnpd.pid
|
||||
.TP
|
||||
.B \-B down up
|
||||
download and upload bitrates reported to clients.
|
||||
.TP
|
||||
.B \-w url
|
||||
presentation url. default is first address on LAN, port 80.
|
||||
.SH "SEE ALSO"
|
||||
minissdpd(1) miniupnpc(3)
|
||||
.SH BUGS
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,105 @@
|
|||
# WAN network interface
|
||||
ext_ifname=eth1
|
||||
#ext_ifname=xl1
|
||||
# if the WAN interface has several IP addresses, you
|
||||
# can specify the one to use below
|
||||
#ext_ip=
|
||||
|
||||
# LAN network interfaces IPs / networks
|
||||
# there can be multiple listening ips for SSDP traffic.
|
||||
# should be under the form nnn.nnn.nnn.nnn/nn
|
||||
# HTTP is available on all interfaces
|
||||
# When MULTIPLE_EXTERNAL_IP is enabled, the external ip
|
||||
# address associated with the subnet follows. for example :
|
||||
# listening_ip=192.168.0.1/24 88.22.44.13
|
||||
#listening_ip=192.168.0.1/24
|
||||
listening_ip=192.168.11.33/24
|
||||
#listening_ip=
|
||||
# port for HTTP (descriptions and SOAP) traffic. set 0 for autoselect.
|
||||
port=0
|
||||
|
||||
# path to the unix socket used to communicate with MiniSSDPd
|
||||
# If running, MiniSSDPd will manage M-SEARCH answering.
|
||||
# default is /var/run/minissdpd.sock
|
||||
#minissdpdsocket=/var/run/minissdpd.sock
|
||||
|
||||
# enable NAT-PMP support (default is no)
|
||||
enable_natpmp=yes
|
||||
|
||||
# enable UPNP support (default is yes)
|
||||
enable_upnp=yes
|
||||
|
||||
# chain names for netfilter (not used for pf or ipf).
|
||||
# default is MINIUPNPD for both
|
||||
#upnp_forward_chain=forwardUPnP
|
||||
#upnp_nat_chain=UPnP
|
||||
|
||||
# lease file location
|
||||
#lease_file=/var/log/upnp.leases
|
||||
|
||||
# bitrates reported by daemon in bits per second
|
||||
bitrate_up=1000000
|
||||
bitrate_down=10000000
|
||||
|
||||
# "secure" mode : when enabled, UPnP client are allowed to add mappings only
|
||||
# to their IP.
|
||||
#secure_mode=yes
|
||||
secure_mode=no
|
||||
|
||||
# default presentation url is http address on port 80
|
||||
# If set to an empty string, no presentationURL element will appear
|
||||
# in the XML description of the device, which prevents MS Windows
|
||||
# from displaying an icon in the "Network Connections" panel.
|
||||
#presentation_url=http://www.mylan/index.php
|
||||
|
||||
# report system uptime instead of daemon uptime
|
||||
system_uptime=yes
|
||||
|
||||
# notify interval in seconds. default is 30 seconds.
|
||||
#notify_interval=240
|
||||
notify_interval=60
|
||||
|
||||
# unused rules cleaning.
|
||||
# never remove any rule before this threshold for the number
|
||||
# of redirections is exceeded. default to 20
|
||||
#clean_ruleset_threshold=10
|
||||
# clean process work interval in seconds. default to 0 (disabled).
|
||||
# a 600 seconds (10 minutes) interval makes sense
|
||||
clean_ruleset_interval=600
|
||||
|
||||
# log packets in pf
|
||||
#packet_log=no
|
||||
|
||||
# ALTQ queue in pf
|
||||
# filter rules must be used for this to be used.
|
||||
# compile with PF_ENABLE_FILTER_RULES (see config.h file)
|
||||
#queue=queue_name1
|
||||
|
||||
# tag name in pf
|
||||
#tag=tag_name1
|
||||
|
||||
# make filter rules in pf quick or not. default is yes
|
||||
# active when compiled with PF_ENABLE_FILTER_RULES (see config.h file)
|
||||
#quickrules=no
|
||||
|
||||
# uuid : generate your own with "make genuuid"
|
||||
uuid=3d3cec3a-8cf0-11e0-98ee-001a6bd2d07b
|
||||
|
||||
# serial and model number the daemon will report to clients
|
||||
# in its XML description
|
||||
serial=12345678
|
||||
model_number=1
|
||||
|
||||
# UPnP permission rules
|
||||
# (allow|deny) (external port range) ip/mask (internal port range)
|
||||
# A port range is <min port>-<max port> or <port> if there is only
|
||||
# one port in the range.
|
||||
# ip/mask format must be nn.nn.nn.nn/nn
|
||||
# it is advised to only allow redirection of port above 1024
|
||||
# and to finish the rule set with "deny 0-65535 0.0.0.0/0 0-65535"
|
||||
allow 1024-65535 192.168.0.0/24 1024-65535
|
||||
allow 1024-65535 192.168.1.0/24 1024-65535
|
||||
allow 1024-65535 192.168.0.0/23 22
|
||||
allow 12345 192.168.7.113/32 54321
|
||||
deny 0-65535 0.0.0.0/0 0-65535
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/* $Id: miniupnpdctl.c,v 1.8 2010/02/15 10:19: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 */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if 0
|
||||
static void sighandler(int sig)
|
||||
{
|
||||
printf("received signal %d\n", sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char * * argv)
|
||||
{
|
||||
/*char test[] = "test!";*/
|
||||
static const char command[] = "show all\n";
|
||||
char buf[256];
|
||||
int l;
|
||||
int s;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
// signal(SIGINT, sighandler);
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s<0)
|
||||
{
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, "/var/run/miniupnpd.ctl",
|
||||
sizeof(addr.sun_path));
|
||||
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
|
||||
{
|
||||
perror("connect");
|
||||
close(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Connected.\n");
|
||||
if(write(s, command, sizeof(command)) < 0)
|
||||
{
|
||||
perror("write");
|
||||
close(s);
|
||||
return 1;
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
l = read(s, buf, sizeof(buf));
|
||||
if(l<0)
|
||||
{
|
||||
perror("read");
|
||||
break;
|
||||
}
|
||||
if(l==0)
|
||||
break;
|
||||
/*printf("%d bytes read\n", l);*/
|
||||
fflush(stdout);
|
||||
if(write(fileno(stdout), buf, l) < 0) {
|
||||
perror("error writing to stdout");
|
||||
}
|
||||
/*printf("\n");*/
|
||||
}
|
||||
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/* $Id: miniupnpdpath.h,v 1.8 2011/05/20 17:51: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 */
|
||||
|
||||
#ifndef __MINIUPNPDPATH_H__
|
||||
#define __MINIUPNPDPATH_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Paths and other URLs in the miniupnpd http server */
|
||||
|
||||
#define ROOTDESC_PATH "/rootDesc.xml"
|
||||
|
||||
#ifdef HAS_DUMMY_SERVICE
|
||||
#define DUMMY_PATH "/dummy.xml"
|
||||
#endif
|
||||
|
||||
#define WANCFG_PATH "/WANCfg.xml"
|
||||
#define WANCFG_CONTROLURL "/ctl/CmnIfCfg"
|
||||
#define WANCFG_EVENTURL "/evt/CmnIfCfg"
|
||||
|
||||
#define WANIPC_PATH "/WANIPCn.xml"
|
||||
#define WANIPC_CONTROLURL "/ctl/IPConn"
|
||||
#define WANIPC_EVENTURL "/evt/IPConn"
|
||||
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
#define L3F_PATH "/L3F.xml"
|
||||
#define L3F_CONTROLURL "/ctl/L3F"
|
||||
#define L3F_EVENTURL "/evt/L3F"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#define WANIP6FC_PATH "/WANIP6FC.xml"
|
||||
#define WANIP6FC_CONTROLURL "/ctl/IP6FCtl"
|
||||
#define WANIP6FC_EVENTURL "/evt/IP6FCtl"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
/* For DeviceProtection introduced in IGD v2 */
|
||||
#define DP_PATH "/DP.xml"
|
||||
#define DP_CONTROLURL "/ctl/DP"
|
||||
#define DP_EVENTURL "/evt/DP"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* $Id: miniupnpdtypes.h,v 1.3 2011/05/13 13:56:18 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2007 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef __MINIUPNPDTYPES_H__
|
||||
#define __MINIUPNPDTYPES_H__
|
||||
|
||||
#include "config.h"
|
||||
#include <netinet/in.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
/* structure and list for storing lan addresses
|
||||
* with ascii representation and mask */
|
||||
struct lan_addr_s {
|
||||
char str[16]; /* example: 192.168.0.1 */
|
||||
struct in_addr addr, mask; /* ip/mask */
|
||||
#ifdef MULTIPLE_EXTERNAL_IP
|
||||
char ext_ip_str[16];
|
||||
struct in_addr ext_ip_addr;
|
||||
#endif
|
||||
LIST_ENTRY(lan_addr_s) list;
|
||||
};
|
||||
LIST_HEAD(lan_addr_list, lan_addr_s);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */
|
||||
/* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2011, 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.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
static int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
static void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
/* to ignore namespace : */
|
||||
if(*p->xml==':')
|
||||
{
|
||||
i = 0;
|
||||
elementname = ++p->xml;
|
||||
}
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(memcmp(p->xml, "<![CDATA[", 9) == 0)
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->xml += 9;
|
||||
data = p->xml;
|
||||
i = 0;
|
||||
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 1) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef __MINIXML_H__
|
||||
#define __MINIXML_H__
|
||||
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
/* $Id: natpmp.c,v 1.26 2011/07/15 07:48:26 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* (c) 2007-2010 Thomas Bernard
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "config.h"
|
||||
#include "natpmp.h"
|
||||
#include "upnpglobalvars.h"
|
||||
#include "getifaddr.h"
|
||||
#include "upnpredirect.h"
|
||||
#include "commonrdr.h"
|
||||
|
||||
#ifdef ENABLE_NATPMP
|
||||
|
||||
int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||
{
|
||||
int snatpmp;
|
||||
snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
|
||||
if(snatpmp<0)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(natpmp): %m");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in natpmp_addr;
|
||||
memset(&natpmp_addr, 0, sizeof(natpmp_addr));
|
||||
natpmp_addr.sin_family = AF_INET;
|
||||
natpmp_addr.sin_port = htons(NATPMP_PORT);
|
||||
//natpmp_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
natpmp_addr.sin_addr.s_addr = addr;
|
||||
if(bind(snatpmp, (struct sockaddr *)&natpmp_addr, sizeof(natpmp_addr)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "bind(natpmp): %m");
|
||||
close(snatpmp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return snatpmp;
|
||||
}
|
||||
|
||||
int OpenAndConfNATPMPSockets(int * sockets)
|
||||
{
|
||||
int i, j;
|
||||
struct lan_addr_s * lan_addr;
|
||||
for(i = 0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
|
||||
{
|
||||
sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr);
|
||||
if(sockets[i] < 0)
|
||||
{
|
||||
for(j=0; j<i; j++)
|
||||
{
|
||||
close(sockets[j]);
|
||||
sockets[j] = -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
|
||||
{
|
||||
#ifndef MULTIPLE_EXTERNAL_IP
|
||||
char tmp[16];
|
||||
|
||||
if(use_ext_ip_addr) {
|
||||
inet_pton(AF_INET, use_ext_ip_addr, resp+8);
|
||||
} else {
|
||||
if(!ext_if_name || ext_if_name[0]=='\0') {
|
||||
resp[3] = 3; /* Network Failure (e.g. NAT box itself
|
||||
* has not obtained a DHCP lease) */
|
||||
} else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN) < 0) {
|
||||
syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name);
|
||||
resp[3] = 3; /* Network Failure (e.g. NAT box itself
|
||||
* has not obtained a DHCP lease) */
|
||||
} else {
|
||||
inet_pton(AF_INET, tmp, resp+8); /* ok */
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct lan_addr_s * lan_addr;
|
||||
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
|
||||
if( (senderaddr & lan_addr->mask.s_addr)
|
||||
== (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) {
|
||||
memcpy(resp+8, &lan_addr->ext_ip_addr,
|
||||
sizeof(lan_addr->ext_ip_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** read the request from the socket, process it and then send the
|
||||
* response back.
|
||||
*/
|
||||
void ProcessIncomingNATPMPPacket(int s)
|
||||
{
|
||||
unsigned char req[32]; /* request udp packet */
|
||||
unsigned char resp[32]; /* response udp packet */
|
||||
int resplen;
|
||||
struct sockaddr_in senderaddr;
|
||||
socklen_t senderaddrlen = sizeof(senderaddr);
|
||||
int n;
|
||||
char senderaddrstr[16];
|
||||
n = recvfrom(s, req, sizeof(req), 0,
|
||||
(struct sockaddr *)&senderaddr, &senderaddrlen);
|
||||
if(n<0) {
|
||||
syslog(LOG_ERR, "recvfrom(natpmp): %m");
|
||||
return;
|
||||
}
|
||||
if(!inet_ntop(AF_INET, &senderaddr.sin_addr,
|
||||
senderaddrstr, sizeof(senderaddrstr))) {
|
||||
syslog(LOG_ERR, "inet_ntop(natpmp): %m");
|
||||
}
|
||||
syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
|
||||
senderaddrstr, ntohs(senderaddr.sin_port), n);
|
||||
if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
|
||||
syslog(LOG_WARNING, "discarding NAT-PMP request (too short) %dBytes",
|
||||
n);
|
||||
return;
|
||||
}
|
||||
if(req[1] & 128) {
|
||||
/* discarding NAT-PMP responses silently */
|
||||
return;
|
||||
}
|
||||
memset(resp, 0, sizeof(resp));
|
||||
resplen = 8;
|
||||
resp[1] = 128 + req[1]; /* response OPCODE is request OPCODE + 128 */
|
||||
/* setting response TIME STAMP :
|
||||
* time elapsed since its port mapping table was initialized on
|
||||
* startup or reset for any other reason */
|
||||
*((uint32_t *)(resp+4)) = htonl(time(NULL) - startup_time);
|
||||
if(req[0] > 0) {
|
||||
/* invalid version */
|
||||
syslog(LOG_WARNING, "unsupported NAT-PMP version : %u",
|
||||
(unsigned)req[0]);
|
||||
resp[3] = 1; /* unsupported version */
|
||||
} else switch(req[1]) {
|
||||
case 0: /* Public address request */
|
||||
syslog(LOG_INFO, "NAT-PMP public address request");
|
||||
FillPublicAddressResponse(resp, senderaddr.sin_addr.s_addr);
|
||||
resplen = 12;
|
||||
break;
|
||||
case 1: /* UDP port mapping request */
|
||||
case 2: /* TCP port mapping request */
|
||||
{
|
||||
unsigned short iport; /* private port */
|
||||
unsigned short eport; /* public port */
|
||||
uint32_t lifetime; /* lifetime=0 => remove port mapping */
|
||||
int r;
|
||||
int proto;
|
||||
char iaddr_old[16];
|
||||
unsigned short iport_old;
|
||||
unsigned int timestamp;
|
||||
|
||||
iport = ntohs(*((uint16_t *)(req+4)));
|
||||
eport = ntohs(*((uint16_t *)(req+6)));
|
||||
lifetime = ntohl(*((uint32_t *)(req+8)));
|
||||
proto = (req[1]==1)?IPPROTO_UDP:IPPROTO_TCP;
|
||||
syslog(LOG_INFO, "NAT-PMP port mapping request : "
|
||||
"%hu->%s:%hu %s lifetime=%us",
|
||||
eport, senderaddrstr, iport,
|
||||
(req[1]==1)?"udp":"tcp", lifetime);
|
||||
if(eport==0)
|
||||
eport = iport;
|
||||
/* TODO: accept port mapping if iport ok but eport not ok
|
||||
* (and set eport correctly) */
|
||||
if(lifetime == 0) {
|
||||
/* remove the mapping */
|
||||
if(iport == 0) {
|
||||
/* remove all the mappings for this client */
|
||||
int index = 0;
|
||||
unsigned short eport2, iport2;
|
||||
char iaddr2[16];
|
||||
int proto2;
|
||||
char desc[64];
|
||||
while(get_redirect_rule_by_index(index, 0,
|
||||
&eport2, iaddr2, sizeof(iaddr2),
|
||||
&iport2, &proto2,
|
||||
desc, sizeof(desc),
|
||||
0, 0, ×tamp, 0, 0) >= 0) {
|
||||
syslog(LOG_DEBUG, "%d %d %hu->'%s':%hu '%s'",
|
||||
index, proto2, eport2, iaddr2, iport2, desc);
|
||||
if(0 == strcmp(iaddr2, senderaddrstr)
|
||||
&& 0 == memcmp(desc, "NAT-PMP", 7)) {
|
||||
r = _upnp_delete_redir(eport2, proto2);
|
||||
/* TODO : check return value */
|
||||
if(r<0) {
|
||||
syslog(LOG_ERR, "failed to remove port mapping");
|
||||
index++;
|
||||
} else {
|
||||
syslog(LOG_INFO, "NAT-PMP %s port %hu mapping removed",
|
||||
proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* To improve the interworking between nat-pmp and
|
||||
* UPnP, we should check that we remove only NAT-PMP
|
||||
* mappings */
|
||||
r = _upnp_delete_redir(eport, proto);
|
||||
/*syslog(LOG_DEBUG, "%hu %d r=%d", eport, proto, r);*/
|
||||
if(r<0) {
|
||||
syslog(LOG_ERR, "Failed to remove NAT-PMP mapping eport %hu, protocol %s",
|
||||
eport, (proto==IPPROTO_TCP)?"TCP":"UDP");
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
}
|
||||
}
|
||||
eport = 0; /* to indicate correct removing of port mapping */
|
||||
} else if(iport==0
|
||||
|| !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr.sin_addr, iport)) {
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
} else do {
|
||||
r = get_redirect_rule(ext_if_name, eport, proto,
|
||||
iaddr_old, sizeof(iaddr_old),
|
||||
&iport_old, 0, 0, 0, 0,
|
||||
×tamp, 0, 0);
|
||||
if(r==0) {
|
||||
if(strcmp(senderaddrstr, iaddr_old)==0
|
||||
&& iport==iport_old) {
|
||||
/* redirection allready existing */
|
||||
syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing",
|
||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
|
||||
/* remove and then add again */
|
||||
if(_upnp_delete_redir(eport, proto) < 0) {
|
||||
syslog(LOG_ERR, "failed to remove port mapping");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
eport++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{ /* do the redirection */
|
||||
char desc[64];
|
||||
#if 0
|
||||
timestamp = (unsigned)(time(NULL) - startup_time)
|
||||
+ lifetime;
|
||||
snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp);
|
||||
#else
|
||||
timestamp = time(NULL) + lifetime;
|
||||
snprintf(desc, sizeof(desc), "NAT-PMP %hu %s",
|
||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp");
|
||||
#endif
|
||||
/* TODO : check return code */
|
||||
if(upnp_redirect_internal(NULL, eport, senderaddrstr,
|
||||
iport, proto, desc,
|
||||
timestamp) < 0) {
|
||||
syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'",
|
||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc);
|
||||
resp[3] = 3; /* Failure */
|
||||
#if 0
|
||||
} else if( !nextnatpmptoclean_eport
|
||||
|| timestamp < nextnatpmptoclean_timestamp) {
|
||||
nextnatpmptoclean_timestamp = timestamp;
|
||||
nextnatpmptoclean_eport = eport;
|
||||
nextnatpmptoclean_proto = proto;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while(r==0);
|
||||
*((uint16_t *)(resp+8)) = htons(iport); /* private port */
|
||||
*((uint16_t *)(resp+10)) = htons(eport); /* public port */
|
||||
*((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */
|
||||
}
|
||||
resplen = 16;
|
||||
break;
|
||||
default:
|
||||
resp[3] = 5; /* Unsupported OPCODE */
|
||||
}
|
||||
n = sendto(s, resp, resplen, 0,
|
||||
(struct sockaddr *)&senderaddr, sizeof(senderaddr));
|
||||
if(n<0) {
|
||||
syslog(LOG_ERR, "sendto(natpmp): %m");
|
||||
} else if(n<resplen) {
|
||||
syslog(LOG_ERR, "sendto(natpmp): sent only %d bytes out of %d",
|
||||
n, resplen);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* iterate through the redirection list to find those who came
|
||||
* from NAT-PMP and select the first to expire */
|
||||
int ScanNATPMPforExpiration()
|
||||
{
|
||||
char desc[64];
|
||||
unsigned short iport, eport;
|
||||
int proto;
|
||||
int r, i;
|
||||
unsigned timestamp;
|
||||
nextnatpmptoclean_eport = 0;
|
||||
nextnatpmptoclean_timestamp = 0;
|
||||
for(i = 0; ; i++) {
|
||||
r = get_redirect_rule_by_index(i, 0, &eport, 0, 0,
|
||||
&iport, &proto, desc, sizeof(desc),
|
||||
×tamp, 0, 0);
|
||||
if(r<0)
|
||||
break;
|
||||
if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) {
|
||||
if( !nextnatpmptoclean_eport
|
||||
|| timestamp < nextnatpmptoclean_timestamp) {
|
||||
nextnatpmptoclean_eport = eport;
|
||||
nextnatpmptoclean_proto = proto;
|
||||
nextnatpmptoclean_timestamp = timestamp;
|
||||
syslog(LOG_DEBUG, "set nextnatpmptoclean_timestamp to %u", timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* remove the next redirection that is expired
|
||||
*/
|
||||
int CleanExpiredNATPMP()
|
||||
{
|
||||
char desc[64];
|
||||
unsigned timestamp;
|
||||
unsigned short iport;
|
||||
if(get_redirect_rule(ext_if_name, nextnatpmptoclean_eport,
|
||||
nextnatpmptoclean_proto,
|
||||
0, 0,
|
||||
&iport, desc, sizeof(desc), ×tamp, 0, 0) < 0)
|
||||
return ScanNATPMPforExpiration();
|
||||
/* check desc - this is important since we keep expiration time as part
|
||||
* of the desc.
|
||||
* If the rule is renewed, timestamp and nextnatpmptoclean_timestamp
|
||||
* can be different. In that case, the rule must not be removed ! */
|
||||
if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) {
|
||||
if(timestamp > nextnatpmptoclean_timestamp)
|
||||
return ScanNATPMPforExpiration();
|
||||
}
|
||||
/* remove redirection then search for next one:) */
|
||||
if(_upnp_delete_redir(nextnatpmptoclean_eport, nextnatpmptoclean_proto)<0)
|
||||
return -1;
|
||||
syslog(LOG_INFO, "Expired NAT-PMP mapping port %hu %s removed",
|
||||
nextnatpmptoclean_eport,
|
||||
nextnatpmptoclean_proto==IPPROTO_TCP?"TCP":"UDP");
|
||||
return ScanNATPMPforExpiration();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SendNATPMPPublicAddressChangeNotification()
|
||||
* should be called when the public IP address changed */
|
||||
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
||||
{
|
||||
struct sockaddr_in sockname;
|
||||
unsigned char notif[12];
|
||||
int j, n;
|
||||
|
||||
notif[0] = 0; /* vers */
|
||||
notif[1] = 128; /* OP code */
|
||||
notif[2] = 0; /* result code */
|
||||
notif[3] = 0; /* result code */
|
||||
/* seconds since "start of epoch" :
|
||||
* time elapsed since the port mapping table was initialized on
|
||||
* startup or reset for any other reason */
|
||||
*((uint32_t *)(notif+4)) = htonl(time(NULL) - startup_time);
|
||||
#ifndef MULTIPLE_EXTERNAL_IP
|
||||
FillPublicAddressResponse(notif, 0);
|
||||
if(notif[3])
|
||||
{
|
||||
syslog(LOG_WARNING, "%s: cannot get public IP address, stopping",
|
||||
"SendNATPMPPublicAddressChangeNotification");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_addr.s_addr = inet_addr(NATPMP_NOTIF_ADDR);
|
||||
|
||||
for(j=0; j<n_sockets; j++)
|
||||
{
|
||||
if(sockets[j] < 0)
|
||||
continue;
|
||||
#ifdef MULTIPLE_EXTERNAL_IP
|
||||
{
|
||||
struct lan_addr_s * lan_addr = lan_addrs.lh_first;
|
||||
int i;
|
||||
for(i=0; i<j; i++)
|
||||
lan_addr = lan_addr->list.le_next;
|
||||
FillPublicAddressResponse(notif, lan_addr->addr.s_addr);
|
||||
}
|
||||
#endif
|
||||
/* Port to use in 2006 version of the NAT-PMP specification */
|
||||
sockname.sin_port = htons(NATPMP_PORT);
|
||||
n = sendto(sockets[j], notif, 12, 0,
|
||||
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
|
||||
"SendNATPMPPublicAddressChangeNotification", sockets[j]);
|
||||
return;
|
||||
}
|
||||
/* Port to use in 2008 version of the NAT-PMP specification */
|
||||
sockname.sin_port = htons(NATPMP_NOTIF_PORT);
|
||||
n = sendto(sockets[j], notif, 12, 0,
|
||||
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
|
||||
"SendNATPMPPublicAddressChangeNotification", sockets[j]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/* $Id: natpmp.h,v 1.8 2011/05/27 21:36:22 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* author : Thomas Bernard
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*/
|
||||
#ifndef __NATPMP_H__
|
||||
#define __NATPMP_H__
|
||||
|
||||
/* The NAT-PMP specification which can be found at the url :
|
||||
* http://files.dns-sd.org/draft-cheshire-nat-pmp.txt
|
||||
* draft version 3 of April 2008
|
||||
* define 5351 as listening port for the gateway,
|
||||
* and the 224.0.0.1 port 5350 as the local link
|
||||
* multicast address for address change announces.
|
||||
* Previous versions of the specification defined 5351
|
||||
* as the port for address change announces. */
|
||||
#define NATPMP_PORT (5351)
|
||||
#define NATPMP_NOTIF_PORT (5350)
|
||||
#define NATPMP_NOTIF_ADDR ("224.0.0.1")
|
||||
|
||||
int OpenAndConfNATPMPSockets(int * sockets);
|
||||
|
||||
void ProcessIncomingNATPMPPacket(int s);
|
||||
|
||||
#if 0
|
||||
int ScanNATPMPforExpiration(void);
|
||||
|
||||
int CleanExpiredNATPMP(void);
|
||||
#endif
|
||||
|
||||
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# $Id: Makefile,v 1.3 2011/03/02 16:04:23 nanard Exp $
|
||||
CFLAGS?=-Wall -g -DDEBUG
|
||||
CC = gcc
|
||||
|
||||
#LIBS = -liptc
|
||||
LIBS = -lip4tc
|
||||
|
||||
ARCH := $(shell uname -m | grep -q "x86_64" && echo 64)
|
||||
ifdef IPTABLESPATH
|
||||
CFLAGS := $(CFLAGS) -I$(IPTABLESPATH)/include/
|
||||
LDFLAGS := $(LDFLAFGS) -L$(IPTABLESPATH)/libiptc/
|
||||
# get iptables version and set IPTABLES_143 macro if needed
|
||||
IPTABLESVERSION := $(shell grep "\#define VERSION" $(IPTABLESPATH)/config.h | tr -d \" |cut -d" " -f3 )
|
||||
IPTABLESVERSION1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 )
|
||||
IPTABLESVERSION2 := $(shell echo $(IPTABLESVERSION) | cut -d. -f2 )
|
||||
IPTABLESVERSION3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 )
|
||||
# test if iptables version >= 1.4.3
|
||||
TEST := $(shell [ \( \( $(IPTABLESVERSION1) -ge 1 \) -a \( $(IPTABLESVERSION2) -ge 4 \) \) -a \( $(IPTABLESVERSION3) -ge 3 \) ] && echo 1 )
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
# the following sucks, but works
|
||||
LIBS = $(IPTABLESPATH)/libiptc/.libs/libip4tc.o
|
||||
#LIBS = $(IPTABLESPATH)/libiptc/.libs/libiptc.a
|
||||
else
|
||||
LIBS = $(IPTABLESPATH)/libiptc/libiptc.a
|
||||
endif
|
||||
else
|
||||
# check for system-wide iptables files. Test if iptables version >= 1.4.3
|
||||
TEST := $(shell test -f /usr/include/iptables/internal.h && grep -q "\#define IPTABLES_VERSION" /usr/include/iptables/internal.h && echo 1)
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
LIBS = -liptc
|
||||
TEST_LIB := $(shell test -f /usr/lib$(ARCH)/libiptc.a && echo 1)
|
||||
ifeq ($(TEST_LIB), 1)
|
||||
LIBS = -liptc /usr/lib$(ARCH)/libiptc.a
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: iptcrdr.o testiptcrdr
|
||||
|
||||
clean:
|
||||
$(RM) *.o testiptcrdr
|
||||
|
||||
testiptcrdr: testiptcrdr.o iptcrdr.o upnpglobalvars.o $(LIBS)
|
||||
|
||||
iptcrdr.o: iptcrdr.c iptcrdr.h
|
||||
|
||||
upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h
|
||||
$(CC) -c -o $@ $<
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_display.sh,v 1.4 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
|
||||
#display all chains relative to miniupnpd
|
||||
$IPTABLES -v -n -t nat -L PREROUTING
|
||||
$IPTABLES -v -n -t nat -L MINIUPNPD
|
||||
$IPTABLES -v -n -t filter -L FORWARD
|
||||
$IPTABLES -v -n -t filter -L MINIUPNPD
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_flush.sh,v 1.3 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
|
||||
#flush all rules owned by miniupnpd
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_init.sh,v 1.5 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
|
||||
#change this parameters :
|
||||
EXTIF=eth0
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
echo "External IP = $EXTIP"
|
||||
|
||||
#adding the MINIUPNPD chain for nat
|
||||
$IPTABLES -t nat -N MINIUPNPD
|
||||
#adding the rule to MINIUPNPD
|
||||
#$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -A PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
|
||||
#adding the MINIUPNPD chain for filter
|
||||
$IPTABLES -t filter -N MINIUPNPD
|
||||
#adding the rule to MINIUPNPD
|
||||
$IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_init_and_clean.sh,v 1.1 2011/05/13 09:58:47 nanard Exp $
|
||||
# Improved Miniupnpd iptables init script.
|
||||
# Checks for state of filter before doing anything..
|
||||
|
||||
EXTIF=eth0
|
||||
IPTABLES=/sbin/iptables
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
NDIRTY="`LC_ALL=C /sbin/iptables -t nat -L -n | grep 'MINIUPNPD' | awk '{printf $1}'`"
|
||||
FDIRTY="`LC_ALL=C /sbin/iptables -t filter -L -n | grep 'MINIUPNPD' | awk '{printf $1}'`"
|
||||
echo "External IP = $EXTIP"
|
||||
|
||||
if [[ $NDIRTY = "MINIUPNPDChain" ]]; then
|
||||
echo "Nat table dirty; Cleaning..."
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
elif [[ $NDIRTY = "Chain" ]]; then
|
||||
echo "Dirty NAT chain but no reference..? Fixsted."
|
||||
$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
else
|
||||
echo "NAT table clean..initalizing.."
|
||||
$IPTABLES -t nat -N MINIUPNPD
|
||||
$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
|
||||
fi
|
||||
if [[ $FDIRTY = "MINIUPNPDChain" ]]; then
|
||||
echo "Filter table dirty; Cleaning..."
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
elif [[ $FDIRTY = "Chain" ]]; then
|
||||
echo "Dirty filter chain but no reference..? Fixsted."
|
||||
$IPTABLES -t filter -I FORWARD 4 -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
else
|
||||
echo "Filter table clean..initalizing.."
|
||||
$IPTABLES -t filter -N MINIUPNPD
|
||||
$IPTABLES -t filter -I FORWARD 4 -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
fi
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_removeall.sh,v 1.5 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
|
||||
#change this parameters :
|
||||
EXTIF=eth0
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
|
||||
#removing the MINIUPNPD chain for nat
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
#rmeoving the rule to MINIUPNPD
|
||||
#$IPTABLES -t nat -D PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -D PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -X MINIUPNPD
|
||||
|
||||
#removing the MINIUPNPD chain for filter
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
#adding the rule to MINIUPNPD
|
||||
$IPTABLES -t filter -D FORWARD -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t filter -X MINIUPNPD
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
|||
/* $Id: iptcrdr.h,v 1.17 2011/06/04 15:44:58 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 __IPTCRDR_H__
|
||||
#define __IPTCRDR_H__
|
||||
|
||||
#include "../commonrdr.h"
|
||||
|
||||
int
|
||||
add_redirect_rule2(const char * ifname,
|
||||
const char * rhost, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport, int proto,
|
||||
const char * desc, unsigned int timestamp);
|
||||
|
||||
int
|
||||
add_filter_rule2(const char * ifname,
|
||||
const char * rhost, const char * iaddr,
|
||||
unsigned short eport, unsigned short iport,
|
||||
int proto, const char * desc);
|
||||
|
||||
int
|
||||
delete_redirect_and_filter_rules(unsigned short eport, int proto);
|
||||
|
||||
/* for debug */
|
||||
int
|
||||
list_redirect_rule(const char * ifname);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* $Id: testiptcrdr.c,v 1.16 2011/03/02 16:04: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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "iptcrdr.h"
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
unsigned short eport, iport;
|
||||
const char * iaddr;
|
||||
printf("Usage %s <ext_port> <internal_ip> <internal_port>\n", argv[0]);
|
||||
|
||||
if(argc<4)
|
||||
return -1;
|
||||
openlog("testiptcrdr", LOG_PERROR|LOG_CONS, LOG_LOCAL0);
|
||||
eport = (unsigned short)atoi(argv[1]);
|
||||
iaddr = argv[2];
|
||||
iport = (unsigned short)atoi(argv[3]);
|
||||
printf("trying to redirect port %hu to %s:%hu\n", eport, iaddr, iport);
|
||||
if(addnatrule(IPPROTO_TCP, eport, iaddr, iport) < 0)
|
||||
return -1;
|
||||
if(add_filter_rule(IPPROTO_TCP, iaddr, iport) < 0)
|
||||
return -1;
|
||||
/* test */
|
||||
{
|
||||
unsigned short p1, p2;
|
||||
char addr[16];
|
||||
int proto2;
|
||||
char desc[256];
|
||||
u_int64_t packets, bytes;
|
||||
desc[0] = '\0';
|
||||
if(get_redirect_rule_by_index(0, "", &p1, addr, sizeof(addr),
|
||||
&p2, &proto2, desc, sizeof(desc),
|
||||
&packets, &bytes) < 0)
|
||||
{
|
||||
printf("rule not found\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("redirected port %hu to %s:%hu proto %d packets=%" PRIu64 " bytes=%" PRIu64 "\n",
|
||||
p1, addr, p2, proto2, packets, bytes);
|
||||
}
|
||||
}
|
||||
printf("trying to list nat rules :\n");
|
||||
list_redirect_rule(argv[1]);
|
||||
printf("deleting\n");
|
||||
delete_redirect_and_filter_rules(eport, IPPROTO_TCP);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* $Id: tiny_nf_nat.h,v 1.1 2011/07/30 13:14:36 nanard Exp $ */
|
||||
/* Only what miniupnpd needs, until linux-libc-dev gains nf_nat.h */
|
||||
|
||||
#ifndef TINY_NF_NAT_H
|
||||
#define TINY_NF_NAT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define IP_NAT_RANGE_MAP_IPS 1
|
||||
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
|
||||
#define IP_NAT_RANGE_PROTO_RANDOM 4
|
||||
#define IP_NAT_RANGE_PERSISTENT 8
|
||||
|
||||
union nf_conntrack_man_proto {
|
||||
__be16 all;
|
||||
struct { __be16 port; } tcp;
|
||||
struct { __be16 port; } udp;
|
||||
struct { __be16 id; } icmp;
|
||||
struct { __be16 port; } dccp;
|
||||
struct { __be16 port; } sctp;
|
||||
struct { __be16 key; } gre;
|
||||
};
|
||||
|
||||
struct nf_nat_range {
|
||||
unsigned int flags;
|
||||
__be32 min_ip, max_ip;
|
||||
union nf_conntrack_man_proto min, max;
|
||||
};
|
||||
|
||||
struct nf_nat_multi_range_compat {
|
||||
unsigned int rangesize;
|
||||
struct nf_nat_range range[1];
|
||||
};
|
||||
|
||||
#define nf_nat_multi_range nf_nat_multi_range_compat
|
||||
|
||||
#endif /*TINY_NF_NAT_H*/
|
|
@ -0,0 +1,195 @@
|
|||
/* $Id: options.c,v 1.20 2008/10/06 13:22:02 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner
|
||||
* (c) 2006 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include "options.h"
|
||||
#include "upnppermissions.h"
|
||||
#include "upnpglobalvars.h"
|
||||
|
||||
struct option * ary_options = NULL;
|
||||
int num_options = 0;
|
||||
|
||||
static const struct {
|
||||
enum upnpconfigoptions id;
|
||||
const char * name;
|
||||
} optionids[] = {
|
||||
{ UPNPEXT_IFNAME, "ext_ifname" },
|
||||
{ UPNPEXT_IP, "ext_ip" },
|
||||
{ UPNPLISTENING_IP, "listening_ip" },
|
||||
{ UPNPPORT, "port" },
|
||||
{ UPNPBITRATE_UP, "bitrate_up" },
|
||||
{ UPNPBITRATE_DOWN, "bitrate_down" },
|
||||
{ UPNPPRESENTATIONURL, "presentation_url" },
|
||||
{ UPNPNOTIFY_INTERVAL, "notify_interval" },
|
||||
{ UPNPSYSTEM_UPTIME, "system_uptime" },
|
||||
{ UPNPPACKET_LOG, "packet_log" },
|
||||
{ UPNPUUID, "uuid"},
|
||||
{ UPNPSERIAL, "serial"},
|
||||
{ UPNPMODEL_NUMBER, "model_number"},
|
||||
{ UPNPCLEANTHRESHOLD, "clean_ruleset_threshold"},
|
||||
{ UPNPCLEANINTERVAL, "clean_ruleset_interval"},
|
||||
#ifdef USE_NETFILTER
|
||||
{ UPNPFORWARDCHAIN, "upnp_forward_chain"},
|
||||
{ UPNPNATCHAIN, "upnp_nat_chain"},
|
||||
#endif
|
||||
#ifdef ENABLE_NATPMP
|
||||
{ UPNPENABLENATPMP, "enable_natpmp"},
|
||||
#endif
|
||||
{ UPNPENABLE, "enable_upnp"},
|
||||
#ifdef USE_PF
|
||||
{ UPNPQUEUE, "queue"},
|
||||
{ UPNPTAG, "tag"},
|
||||
#endif
|
||||
#ifdef PF_ENABLE_FILTER_RULES
|
||||
{ UPNPQUICKRULES, "quickrules" },
|
||||
#endif
|
||||
#ifdef ENABLE_LEASEFILE
|
||||
{ UPNPLEASEFILE, "lease_file"},
|
||||
#endif
|
||||
{ UPNPMINISSDPDSOCKET, "minissdpdsocket"},
|
||||
{ UPNPSECUREMODE, "secure_mode"}
|
||||
};
|
||||
|
||||
int
|
||||
readoptionsfile(const char * fname)
|
||||
{
|
||||
FILE *hfile = NULL;
|
||||
char buffer[1024];
|
||||
char *equals;
|
||||
char *name;
|
||||
char *value;
|
||||
char *t;
|
||||
int linenum = 0;
|
||||
int i;
|
||||
enum upnpconfigoptions id;
|
||||
|
||||
if(!fname || (strlen(fname) == 0))
|
||||
return -1;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Reading configuration from file %s\n", fname);
|
||||
#endif
|
||||
|
||||
if(!(hfile = fopen(fname, "r")))
|
||||
return -1;
|
||||
|
||||
if(ary_options != NULL)
|
||||
{
|
||||
free(ary_options);
|
||||
num_options = 0;
|
||||
}
|
||||
|
||||
while(fgets(buffer, sizeof(buffer), hfile))
|
||||
{
|
||||
linenum++;
|
||||
t = strchr(buffer, '\n');
|
||||
if(t)
|
||||
{
|
||||
*t = '\0';
|
||||
t--;
|
||||
while((t >= buffer) && isspace(*t))
|
||||
{
|
||||
*t = '\0';
|
||||
t--;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip leading whitespaces */
|
||||
name = buffer;
|
||||
while(isspace(*name))
|
||||
name++;
|
||||
|
||||
/* check for comments or empty lines */
|
||||
if(name[0] == '#' || name[0] == '\0') continue;
|
||||
|
||||
/* check for UPnP permissions rule */
|
||||
if(0 == memcmp(name, "allow", 5) || 0 == memcmp(name, "deny", 4))
|
||||
{
|
||||
upnppermlist = realloc(upnppermlist,
|
||||
sizeof(struct upnpperm) * (num_upnpperm+1));
|
||||
/* parse the rule */
|
||||
if(read_permission_line(upnppermlist + num_upnpperm, name) >= 0)
|
||||
{
|
||||
num_upnpperm++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "parsing error file %s line %d : %s\n",
|
||||
fname, linenum, name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(!(equals = strchr(name, '=')))
|
||||
{
|
||||
fprintf(stderr, "parsing error file %s line %d : %s\n",
|
||||
fname, linenum, name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* remove ending whitespaces */
|
||||
for(t=equals-1; t>name && isspace(*t); t--)
|
||||
*t = '\0';
|
||||
|
||||
*equals = '\0';
|
||||
value = equals+1;
|
||||
|
||||
/* skip leading whitespaces */
|
||||
while(isspace(*value))
|
||||
value++;
|
||||
|
||||
id = UPNP_INVALID;
|
||||
for(i=0; i<sizeof(optionids)/sizeof(optionids[0]); i++)
|
||||
{
|
||||
/*printf("%2d %2d %s %s\n", i, optionids[i].id, name,
|
||||
optionids[i].name); */
|
||||
|
||||
if(0 == strcmp(name, optionids[i].name))
|
||||
{
|
||||
id = optionids[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(id == UPNP_INVALID)
|
||||
{
|
||||
fprintf(stderr, "parsing error file %s line %d : %s=%s\n",
|
||||
fname, linenum, name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_options += 1;
|
||||
ary_options = (struct option *) realloc(ary_options, num_options * sizeof(struct option));
|
||||
|
||||
ary_options[num_options-1].id = id;
|
||||
strncpy(ary_options[num_options-1].value, value, MAX_OPTION_VALUE_LEN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(hfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
freeoptions(void)
|
||||
{
|
||||
if(ary_options)
|
||||
{
|
||||
free(ary_options);
|
||||
ary_options = NULL;
|
||||
num_options = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* $Id: options.h,v 1.15 2008/10/06 13:22:02 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner
|
||||
* (c) 2006 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef __OPTIONS_H__
|
||||
#define __OPTIONS_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* enum of option available in the miniupnpd.conf */
|
||||
enum upnpconfigoptions {
|
||||
UPNP_INVALID = 0,
|
||||
UPNPEXT_IFNAME = 1, /* ext_ifname */
|
||||
UPNPEXT_IP, /* ext_ip */
|
||||
UPNPLISTENING_IP, /* listening_ip */
|
||||
UPNPPORT, /* "port" */
|
||||
UPNPBITRATE_UP, /* "bitrate_up" */
|
||||
UPNPBITRATE_DOWN, /* "bitrate_down" */
|
||||
UPNPPRESENTATIONURL, /* presentation_url */
|
||||
UPNPNOTIFY_INTERVAL, /* notify_interval */
|
||||
UPNPSYSTEM_UPTIME, /* "system_uptime" */
|
||||
UPNPPACKET_LOG, /* "packet_log" */
|
||||
UPNPUUID, /* uuid */
|
||||
UPNPSERIAL, /* serial */
|
||||
UPNPMODEL_NUMBER, /* model_number */
|
||||
UPNPCLEANTHRESHOLD, /* clean_ruleset_threshold */
|
||||
UPNPCLEANINTERVAL, /* clean_ruleset_interval */
|
||||
UPNPENABLENATPMP, /* enable_natpmp */
|
||||
#ifdef USE_NETFILTER
|
||||
UPNPFORWARDCHAIN,
|
||||
UPNPNATCHAIN,
|
||||
#endif
|
||||
#ifdef USE_PF
|
||||
UPNPQUEUE, /* queue */
|
||||
UPNPTAG, /* tag */
|
||||
#endif
|
||||
#ifdef PF_ENABLE_FILTER_RULES
|
||||
UPNPQUICKRULES, /* quickrules */
|
||||
#endif
|
||||
UPNPSECUREMODE, /* secure_mode */
|
||||
#ifdef ENABLE_LEASEFILE
|
||||
UPNPLEASEFILE, /* lease_file */
|
||||
#endif
|
||||
UPNPMINISSDPDSOCKET, /* minissdpdsocket */
|
||||
UPNPENABLE /* enable_upnp */
|
||||
};
|
||||
|
||||
/* readoptionsfile()
|
||||
* parse and store the option file values
|
||||
* returns: 0 success, -1 failure */
|
||||
int
|
||||
readoptionsfile(const char * fname);
|
||||
|
||||
/* freeoptions()
|
||||
* frees memory allocated to option values */
|
||||
void
|
||||
freeoptions(void);
|
||||
|
||||
#define MAX_OPTION_VALUE_LEN (80)
|
||||
struct option
|
||||
{
|
||||
enum upnpconfigoptions id;
|
||||
char value[MAX_OPTION_VALUE_LEN];
|
||||
};
|
||||
|
||||
extern struct option * ary_options;
|
||||
extern int num_options;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# $Id: Makefile,v 1.2 2010/03/08 17:10:37 nanard Exp $
|
||||
# made for GNU Make (and BSD make)
|
||||
CFLAGS = -Wall -g -DTEST
|
||||
EXECUTABLES = testobsdrdr
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXECUTABLES)
|
||||
|
||||
testobsdrdr: testobsdrdr.o obsdrdr.o
|
||||
$(CC) $(CFLAGS) -o $@ $>
|
||||
|
||||
obsdrdr.o: obsdrdr.c obsdrdr.h
|
||||
|
||||
testobsdrdr.o: testobsdrdr.c obsdrdr.h
|
||||
|
|
@ -0,0 +1,910 @@
|
|||
/* $Id: obsdrdr.c,v 1.67 2011/06/22 21:20:27 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2010 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
/*
|
||||
* pf rules created (with ext_if = xl1)
|
||||
* - OpenBSD up to version 4.6 :
|
||||
* rdr pass on xl1 inet proto udp from any to any port = 54321 \
|
||||
* label "test label" -> 192.168.0.141 port 12345
|
||||
* or a rdr rule + a pass rule
|
||||
*
|
||||
* - OpenBSD starting from version 4.7
|
||||
* match in on xl1 inet proto udp from any to any port 54321 \
|
||||
* label "test label" rdr-to 192.168.0.141 port 12345
|
||||
* or
|
||||
* pass in quick on xl1 inet proto udp from any to any port 54321 \
|
||||
* label "test label" rdr-to 192.168.0.141 port 12345
|
||||
*
|
||||
*
|
||||
*
|
||||
* Macros/#defines :
|
||||
* - PF_ENABLE_FILTER_RULES
|
||||
* If set, two rules are created : rdr + pass. Else a rdr/pass rule
|
||||
* is created.
|
||||
* - USE_IFNAME_IN_RULES
|
||||
* If set the interface name is set in the rule.
|
||||
* - PFRULE_INOUT_COUNTS
|
||||
* Must be set with OpenBSD version 3.8 and up.
|
||||
* - PFRULE_HAS_RTABLEID
|
||||
* Must be set with OpenBSD version 4.0 and up.
|
||||
* - PF_NEWSSTYLE
|
||||
* Must be set with OpenBSD version 4.7 and up.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifdef __DragonFly__
|
||||
#include <net/pf/pfvar.h>
|
||||
#else
|
||||
#include <net/pfvar.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "obsdrdr.h"
|
||||
#include "../upnpglobalvars.h"
|
||||
|
||||
/* list too keep timestamps for port mappings having a lease duration */
|
||||
struct timestamp_entry {
|
||||
struct timestamp_entry * next;
|
||||
unsigned int timestamp;
|
||||
unsigned short eport;
|
||||
short protocol;
|
||||
};
|
||||
|
||||
static struct timestamp_entry * timestamp_list = NULL;
|
||||
|
||||
static unsigned int
|
||||
get_timestamp(unsigned short eport, int proto)
|
||||
{
|
||||
struct timestamp_entry * e;
|
||||
e = timestamp_list;
|
||||
while(e) {
|
||||
if(e->eport == eport && e->protocol == (short)proto)
|
||||
return e->timestamp;
|
||||
e = e->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_timestamp_entry(unsigned short eport, int proto)
|
||||
{
|
||||
struct timestamp_entry * e;
|
||||
struct timestamp_entry * * p;
|
||||
p = ×tamp_list;
|
||||
e = *p;
|
||||
while(e) {
|
||||
if(e->eport == eport && e->protocol == (short)proto) {
|
||||
/* remove the entry */
|
||||
*p = e->next;
|
||||
free(e);
|
||||
return;
|
||||
}
|
||||
p = &(e->next);
|
||||
e = *p;
|
||||
}
|
||||
}
|
||||
|
||||
/* anchor name */
|
||||
static const char anchor_name[] = "miniupnpd";
|
||||
|
||||
/* /dev/pf when opened */
|
||||
static int dev = -1;
|
||||
|
||||
/* shutdown_redirect() :
|
||||
* close the /dev/pf device */
|
||||
void
|
||||
shutdown_redirect(void)
|
||||
{
|
||||
if(close(dev)<0)
|
||||
syslog(LOG_ERR, "close(\"/dev/pf\"): %m");
|
||||
dev = -1;
|
||||
}
|
||||
|
||||
/* open the device */
|
||||
int
|
||||
init_redirect(void)
|
||||
{
|
||||
struct pf_status status;
|
||||
if(dev>=0)
|
||||
shutdown_redirect();
|
||||
dev = open("/dev/pf", O_RDWR);
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "open(\"/dev/pf\"): %m");
|
||||
return -1;
|
||||
}
|
||||
if(ioctl(dev, DIOCGETSTATUS, &status)<0) {
|
||||
syslog(LOG_ERR, "DIOCGETSTATUS: %m");
|
||||
return -1;
|
||||
}
|
||||
if(!status.running) {
|
||||
syslog(LOG_ERR, "pf is disabled");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if TEST
|
||||
/* for debug */
|
||||
int
|
||||
clear_redirect_rules(void)
|
||||
{
|
||||
struct pfioc_trans io;
|
||||
struct pfioc_trans_e ioe;
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
memset(&ioe, 0, sizeof(ioe));
|
||||
io.size = 1;
|
||||
io.esize = sizeof(ioe);
|
||||
io.array = &ioe;
|
||||
#ifndef PF_NEWSTYLE
|
||||
ioe.rs_num = PF_RULESET_RDR;
|
||||
#else
|
||||
ioe.type = PF_TRANS_RULESET;
|
||||
#endif
|
||||
strlcpy(ioe.anchor, anchor_name, MAXPATHLEN);
|
||||
if(ioctl(dev, DIOCXBEGIN, &io) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add_redirect_rule2() :
|
||||
* create a rdr rule */
|
||||
int
|
||||
add_redirect_rule2(const char * ifname,
|
||||
const char * rhost, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport, int proto,
|
||||
const char * desc, unsigned int timestamp)
|
||||
{
|
||||
int r;
|
||||
struct pfioc_rule pcr;
|
||||
#ifndef PF_NEWSTYLE
|
||||
struct pfioc_pooladdr pp;
|
||||
struct pf_pooladdr *a;
|
||||
#endif
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
r = 0;
|
||||
memset(&pcr, 0, sizeof(pcr));
|
||||
strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
|
||||
|
||||
#ifndef PF_NEWSTYLE
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
||||
if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr.pool_ticket = pp.ticket;
|
||||
#else
|
||||
if(1)
|
||||
{
|
||||
pcr.rule.direction = PF_IN;
|
||||
//pcr.rule.src.addr.type = PF_ADDR_NONE;
|
||||
pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
|
||||
pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
|
||||
pcr.rule.nat.addr.type = PF_ADDR_NONE;
|
||||
pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
|
||||
#endif
|
||||
|
||||
pcr.rule.dst.port_op = PF_OP_EQ;
|
||||
pcr.rule.dst.port[0] = htons(eport);
|
||||
pcr.rule.dst.port[1] = htons(eport);
|
||||
#ifndef PF_NEWSTYLE
|
||||
pcr.rule.action = PF_RDR;
|
||||
#ifndef PF_ENABLE_FILTER_RULES
|
||||
pcr.rule.natpass = 1;
|
||||
#else
|
||||
pcr.rule.natpass = 0;
|
||||
#endif
|
||||
#else
|
||||
#ifndef PF_ENABLE_FILTER_RULES
|
||||
pcr.rule.action = PF_PASS;
|
||||
#else
|
||||
pcr.rule.action = PF_MATCH;
|
||||
#endif
|
||||
#endif
|
||||
pcr.rule.af = AF_INET;
|
||||
#ifdef USE_IFNAME_IN_RULES
|
||||
if(ifname)
|
||||
strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
|
||||
#endif
|
||||
pcr.rule.proto = proto;
|
||||
pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
|
||||
#ifdef PFRULE_HAS_RTABLEID
|
||||
pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
|
||||
#endif
|
||||
pcr.rule.quick = 1;
|
||||
pcr.rule.keep_state = PF_STATE_NORMAL;
|
||||
if(tag)
|
||||
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
|
||||
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
|
||||
if(rhost && rhost[0] != '\0' && rhost[0] != '*')
|
||||
{
|
||||
inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
|
||||
pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
|
||||
}
|
||||
#ifndef PF_NEWSTYLE
|
||||
pcr.rule.rpool.proxy_port[0] = iport;
|
||||
pcr.rule.rpool.proxy_port[1] = iport;
|
||||
TAILQ_INIT(&pcr.rule.rpool.list);
|
||||
a = calloc(1, sizeof(struct pf_pooladdr));
|
||||
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
|
||||
a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
|
||||
TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
|
||||
|
||||
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
|
||||
if(ioctl(dev, DIOCADDADDR, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#else
|
||||
pcr.rule.rdr.proxy_port[0] = iport;
|
||||
pcr.rule.rdr.proxy_port[1] = iport;
|
||||
inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr);
|
||||
pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
|
||||
if(1)
|
||||
{
|
||||
#endif
|
||||
pcr.action = PF_CHANGE_GET_TICKET;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr.action = PF_CHANGE_ADD_TAIL;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
|
||||
r = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef PF_NEWSTYLE
|
||||
free(a);
|
||||
#endif
|
||||
}
|
||||
if(r == 0 && timestamp > 0)
|
||||
{
|
||||
struct timestamp_entry * tmp;
|
||||
tmp = malloc(sizeof(struct timestamp_entry));
|
||||
if(tmp)
|
||||
{
|
||||
tmp->next = timestamp_list;
|
||||
tmp->timestamp = timestamp;
|
||||
tmp->eport = eport;
|
||||
tmp->protocol = (short)proto;
|
||||
timestamp_list = tmp;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* thanks to Seth Mos for this function */
|
||||
int
|
||||
add_filter_rule2(const char * ifname,
|
||||
const char * rhost, const char * iaddr,
|
||||
unsigned short eport, unsigned short iport,
|
||||
int proto, const char * desc)
|
||||
{
|
||||
#ifndef PF_ENABLE_FILTER_RULES
|
||||
return 0;
|
||||
#else
|
||||
int r;
|
||||
struct pfioc_rule pcr;
|
||||
#ifndef PF_NEWSTYLE
|
||||
struct pfioc_pooladdr pp;
|
||||
struct pf_pooladdr *a;
|
||||
#endif
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
r = 0;
|
||||
memset(&pcr, 0, sizeof(pcr));
|
||||
strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
|
||||
|
||||
#ifndef PF_NEWSTYLE
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
||||
if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr.pool_ticket = pp.ticket;
|
||||
#else
|
||||
if(1)
|
||||
{
|
||||
#endif
|
||||
|
||||
pcr.rule.dst.port_op = PF_OP_EQ;
|
||||
pcr.rule.dst.port[0] = htons(eport);
|
||||
pcr.rule.direction = PF_IN;
|
||||
pcr.rule.action = PF_PASS;
|
||||
pcr.rule.af = AF_INET;
|
||||
#ifdef USE_IFNAME_IN_RULES
|
||||
if(ifname)
|
||||
strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
|
||||
#endif
|
||||
pcr.rule.proto = proto;
|
||||
pcr.rule.quick = (GETFLAG(PFNOQUICKRULESMASK))?0:1;
|
||||
pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
|
||||
/* see the discussion on the forum :
|
||||
* http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
|
||||
pcr.rule.flags = TH_SYN;
|
||||
pcr.rule.flagset = (TH_SYN|TH_ACK);
|
||||
#ifdef PFRULE_HAS_RTABLEID
|
||||
pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
|
||||
#endif
|
||||
pcr.rule.keep_state = 1;
|
||||
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
|
||||
if(queue)
|
||||
strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
|
||||
if(tag)
|
||||
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
|
||||
|
||||
if(rhost && rhost[0] != '\0' && rhost[0] != '*')
|
||||
{
|
||||
inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
|
||||
pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
|
||||
}
|
||||
#ifndef PF_NEWSTYLE
|
||||
pcr.rule.rpool.proxy_port[0] = eport;
|
||||
a = calloc(1, sizeof(struct pf_pooladdr));
|
||||
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
|
||||
a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
|
||||
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
|
||||
TAILQ_INIT(&pcr.rule.rpool.list);
|
||||
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
|
||||
TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
|
||||
|
||||
/* we have any - any port = # keep state label */
|
||||
/* we want any - iaddr port = # keep state label */
|
||||
/* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
|
||||
|
||||
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
|
||||
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
|
||||
if(ioctl(dev, DIOCADDADDR, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#else
|
||||
if(1)
|
||||
{
|
||||
#endif
|
||||
pcr.action = PF_CHANGE_GET_TICKET;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr.action = PF_CHANGE_ADD_TAIL;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
|
||||
r = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef PF_NEWSTYLE
|
||||
free(a);
|
||||
#endif
|
||||
}
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* get_redirect_rule()
|
||||
* return value : 0 success (found)
|
||||
* -1 = error or rule not found */
|
||||
int
|
||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes)
|
||||
{
|
||||
int i, n;
|
||||
struct pfioc_rule pr;
|
||||
#ifndef PF_NEWSTYLE
|
||||
struct pfioc_pooladdr pp;
|
||||
#endif
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
#ifndef PF_NEWSTYLE
|
||||
pr.rule.action = PF_RDR;
|
||||
#endif
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
n = pr.nr;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||
goto error;
|
||||
}
|
||||
if( (eport == ntohs(pr.rule.dst.port[0]))
|
||||
&& (eport == ntohs(pr.rule.dst.port[1]))
|
||||
&& (pr.rule.proto == proto) )
|
||||
{
|
||||
#ifndef PF_NEWSTYLE
|
||||
*iport = pr.rule.rpool.proxy_port[0];
|
||||
#else
|
||||
*iport = pr.rule.rdr.proxy_port[0];
|
||||
#endif
|
||||
if(desc)
|
||||
strlcpy(desc, pr.rule.label, desclen);
|
||||
#ifdef PFRULE_INOUT_COUNTS
|
||||
if(packets)
|
||||
*packets = pr.rule.packets[0] + pr.rule.packets[1];
|
||||
if(bytes)
|
||||
*bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
|
||||
#else
|
||||
if(packets)
|
||||
*packets = pr.rule.packets;
|
||||
if(bytes)
|
||||
*bytes = pr.rule.bytes;
|
||||
#endif
|
||||
#ifndef PF_NEWSTYLE
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
||||
pp.r_action = PF_RDR;
|
||||
pp.r_num = i;
|
||||
pp.ticket = pr.ticket;
|
||||
if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
if(pp.nr != 1)
|
||||
{
|
||||
syslog(LOG_NOTICE, "No address associated with pf rule");
|
||||
goto error;
|
||||
}
|
||||
pp.nr = 0; /* first */
|
||||
if(ioctl(dev, DIOCGETADDR, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
|
||||
iaddr, iaddrlen);
|
||||
#else
|
||||
inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
|
||||
iaddr, iaddrlen);
|
||||
#endif
|
||||
if(rhost && rhostlen > 0)
|
||||
{
|
||||
if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
|
||||
{
|
||||
rhost[0] = '\0'; /* empty string */
|
||||
}
|
||||
else
|
||||
{
|
||||
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
|
||||
rhost, rhostlen);
|
||||
}
|
||||
}
|
||||
if(timestamp)
|
||||
*timestamp = get_timestamp(eport, proto);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
|
||||
{
|
||||
int i, n;
|
||||
struct pfioc_rule pr;
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
#ifndef PF_NEWSTYLE
|
||||
pr.rule.action = PF_RDR;
|
||||
#endif
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
n = pr.nr;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||
goto error;
|
||||
}
|
||||
if( (eport == ntohs(pr.rule.dst.port[0]))
|
||||
&& (eport == ntohs(pr.rule.dst.port[1]))
|
||||
&& (pr.rule.proto == proto) )
|
||||
{
|
||||
pr.action = PF_CHANGE_GET_TICKET;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
||||
goto error;
|
||||
}
|
||||
pr.action = PF_CHANGE_REMOVE;
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
|
||||
goto error;
|
||||
}
|
||||
remove_timestamp_entry(eport, proto);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
delete_filter_rule(const char * ifname, unsigned short eport, int proto)
|
||||
{
|
||||
#ifndef PF_ENABLE_FILTER_RULES
|
||||
return 0;
|
||||
#else
|
||||
int i, n;
|
||||
struct pfioc_rule pr;
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
pr.rule.action = PF_PASS;
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
n = pr.nr;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||
goto error;
|
||||
}
|
||||
if( (eport == ntohs(pr.rule.dst.port[0]))
|
||||
&& (pr.rule.proto == proto) )
|
||||
{
|
||||
pr.action = PF_CHANGE_GET_TICKET;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
|
||||
goto error;
|
||||
}
|
||||
pr.action = PF_CHANGE_REMOVE;
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
get_redirect_rule_by_index(int index,
|
||||
char * ifname, unsigned short * eport,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
int * proto, char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes)
|
||||
{
|
||||
int n;
|
||||
struct pfioc_rule pr;
|
||||
#ifndef PF_NEWSTYLE
|
||||
struct pfioc_pooladdr pp;
|
||||
#endif
|
||||
if(index < 0)
|
||||
return -1;
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return -1;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
#ifndef PF_NEWSTYLE
|
||||
pr.rule.action = PF_RDR;
|
||||
#endif
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
n = pr.nr;
|
||||
if(index >= n)
|
||||
goto error;
|
||||
pr.nr = index;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||
goto error;
|
||||
}
|
||||
*proto = pr.rule.proto;
|
||||
*eport = ntohs(pr.rule.dst.port[0]);
|
||||
#ifndef PF_NEWSTYLE
|
||||
*iport = pr.rule.rpool.proxy_port[0];
|
||||
#else
|
||||
*iport = pr.rule.rdr.proxy_port[0];
|
||||
#endif
|
||||
if(ifname)
|
||||
strlcpy(ifname, pr.rule.ifname, IFNAMSIZ);
|
||||
if(desc)
|
||||
strlcpy(desc, pr.rule.label, desclen);
|
||||
#ifdef PFRULE_INOUT_COUNTS
|
||||
if(packets)
|
||||
*packets = pr.rule.packets[0] + pr.rule.packets[1];
|
||||
if(bytes)
|
||||
*bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
|
||||
#else
|
||||
if(packets)
|
||||
*packets = pr.rule.packets;
|
||||
if(bytes)
|
||||
*bytes = pr.rule.bytes;
|
||||
#endif
|
||||
#ifndef PF_NEWSTYLE
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
||||
pp.r_action = PF_RDR;
|
||||
pp.r_num = index;
|
||||
pp.ticket = pr.ticket;
|
||||
if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
if(pp.nr != 1)
|
||||
{
|
||||
syslog(LOG_NOTICE, "No address associated with pf rule");
|
||||
goto error;
|
||||
}
|
||||
pp.nr = 0; /* first */
|
||||
if(ioctl(dev, DIOCGETADDR, &pp) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
|
||||
goto error;
|
||||
}
|
||||
inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
|
||||
iaddr, iaddrlen);
|
||||
#else
|
||||
inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
|
||||
iaddr, iaddrlen);
|
||||
#endif
|
||||
if(rhost && rhostlen > 0)
|
||||
{
|
||||
if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
|
||||
{
|
||||
rhost[0] = '\0'; /* empty string */
|
||||
}
|
||||
else
|
||||
{
|
||||
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
|
||||
rhost, rhostlen);
|
||||
}
|
||||
}
|
||||
if(timestamp)
|
||||
*timestamp = get_timestamp(*eport, *proto);
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* return an (malloc'ed) array of "external" port for which there is
|
||||
* a port mapping. number is the size of the array */
|
||||
unsigned short *
|
||||
get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||
int proto, unsigned int * number)
|
||||
{
|
||||
unsigned short * array;
|
||||
unsigned int capacity;
|
||||
int i, n;
|
||||
unsigned short eport;
|
||||
struct pfioc_rule pr;
|
||||
|
||||
*number = 0;
|
||||
if(dev<0) {
|
||||
syslog(LOG_ERR, "pf device is not open");
|
||||
return NULL;
|
||||
}
|
||||
capacity = 128;
|
||||
array = calloc(capacity, sizeof(unsigned short));
|
||||
if(!array)
|
||||
{
|
||||
syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
|
||||
return NULL;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
#ifndef PF_NEWSTYLE
|
||||
pr.rule.action = PF_RDR;
|
||||
#endif
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
|
||||
free(array);
|
||||
return NULL;
|
||||
}
|
||||
n = pr.nr;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||
continue;
|
||||
}
|
||||
eport = ntohs(pr.rule.dst.port[0]);
|
||||
if( (eport == ntohs(pr.rule.dst.port[1]))
|
||||
&& (pr.rule.proto == proto)
|
||||
&& (startport <= eport) && (eport <= endport) )
|
||||
{
|
||||
if(*number >= capacity)
|
||||
{
|
||||
/* need to increase the capacity of the array */
|
||||
capacity += 128;
|
||||
array = realloc(array, sizeof(unsigned short)*capacity);
|
||||
if(!array)
|
||||
{
|
||||
syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
|
||||
*number = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
array[*number] = eport;
|
||||
(*number)++;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/* this function is only for testing */
|
||||
#if TEST
|
||||
void
|
||||
list_rules(void)
|
||||
{
|
||||
char buf[32];
|
||||
int i, n;
|
||||
struct pfioc_rule pr;
|
||||
#ifndef PF_NEWSTYLE
|
||||
struct pfioc_pooladdr pp;
|
||||
#endif
|
||||
|
||||
if(dev<0)
|
||||
{
|
||||
perror("pf dev not open");
|
||||
return ;
|
||||
}
|
||||
memset(&pr, 0, sizeof(pr));
|
||||
strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
|
||||
pr.rule.action = PF_RDR;
|
||||
if(ioctl(dev, DIOCGETRULES, &pr) < 0)
|
||||
perror("DIOCGETRULES");
|
||||
printf("ticket = %d, nr = %d\n", pr.ticket, pr.nr);
|
||||
n = pr.nr;
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
printf("-- rule %d --\n", i);
|
||||
pr.nr = i;
|
||||
if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
perror("DIOCGETRULE");
|
||||
printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n",
|
||||
pr.rule.ifname,
|
||||
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, buf, 32);
|
||||
(int)ntohs(pr.rule.dst.port[0]),
|
||||
(int)ntohs(pr.rule.dst.port[1]),
|
||||
#ifndef PF_NEWSTYLE
|
||||
(int)pr.rule.rpool.proxy_port[0],
|
||||
(int)pr.rule.rpool.proxy_port[1],
|
||||
#else
|
||||
(int)pr.rule.rdr.proxy_port[0],
|
||||
(int)pr.rule.rdr.proxy_port[1],
|
||||
#endif
|
||||
(int)pr.rule.proto,
|
||||
(int)pr.rule.keep_state,
|
||||
(int)pr.rule.action);
|
||||
printf(" description: \"%s\"\n", pr.rule.label);
|
||||
#ifndef PF_NEWSTYLE
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
|
||||
pp.r_action = PF_RDR;
|
||||
pp.r_num = i;
|
||||
pp.ticket = pr.ticket;
|
||||
if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
|
||||
perror("DIOCGETADDRS");
|
||||
printf(" nb pool addr = %d ticket=%d\n", pp.nr, pp.ticket);
|
||||
/*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
|
||||
perror("DIOCGETRULE"); */
|
||||
pp.nr = 0; /* first */
|
||||
if(ioctl(dev, DIOCGETADDR, &pp) < 0)
|
||||
perror("DIOCGETADDR");
|
||||
/* addr.v.a.addr.v4.s_addr */
|
||||
printf(" %s\n", inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, buf, 32));
|
||||
#else
|
||||
printf(" rule_flag=%08x action=%d direction=%d log=%d logif=%d "
|
||||
"quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
|
||||
pr.rule.rule_flag, pr.rule.action, pr.rule.direction,
|
||||
pr.rule.log, pr.rule.logif, pr.rule.quick, pr.rule.ifnot,
|
||||
pr.rule.af, pr.rule.type, pr.rule.code,
|
||||
pr.rule.rdr.port_op, pr.rule.rdr.opts);
|
||||
printf(" %s\n", inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, buf, 32));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/* $Id: obsdrdr.h,v 1.19 2011/06/04 15:47:18 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 __OBSDRDR_H__
|
||||
#define __OBSDRDR_H__
|
||||
|
||||
#include "../commonrdr.h"
|
||||
|
||||
/* add_redirect_rule2() uses DIOCCHANGERULE ioctl
|
||||
* proto can take the values IPPROTO_UDP or IPPROTO_TCP
|
||||
*/
|
||||
int
|
||||
add_redirect_rule2(const char * ifname,
|
||||
const char * rhost, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport, int proto,
|
||||
const char * desc, unsigned int timestamp);
|
||||
|
||||
/* add_filter_rule2() uses DIOCCHANGERULE ioctl
|
||||
* proto can take the values IPPROTO_UDP or IPPROTO_TCP
|
||||
*/
|
||||
int
|
||||
add_filter_rule2(const char * ifname,
|
||||
const char * rhost, const char * iaddr,
|
||||
unsigned short eport, unsigned short iport,
|
||||
int proto, const char * desc);
|
||||
|
||||
|
||||
/* get_redirect_rule() gets internal IP and port from
|
||||
* interface, external port and protocl
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
|
||||
int
|
||||
get_redirect_rule_by_index(int index,
|
||||
char * ifname, unsigned short * eport,
|
||||
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||
int * proto, char * desc, int desclen,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
#endif
|
||||
|
||||
/* delete_redirect_rule()
|
||||
*/
|
||||
int
|
||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
/* delete_filter_rule()
|
||||
*/
|
||||
int
|
||||
delete_filter_rule(const char * ifname, unsigned short eport, int proto);
|
||||
|
||||
int
|
||||
clear_redirect_rules(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/* $Id: testobsdrdr.c,v 1.22 2011/06/04 16:45:22 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "obsdrdr.h"
|
||||
|
||||
/*int logpackets = 1;*/
|
||||
int runtime_flags = 0;
|
||||
const char * tag = 0;
|
||||
|
||||
void
|
||||
list_rules(void);
|
||||
|
||||
void
|
||||
list_eports_tcp(void)
|
||||
{
|
||||
unsigned short * port_list;
|
||||
unsigned int number = 0;
|
||||
unsigned int i;
|
||||
port_list = get_portmappings_in_range(0, 65535, IPPROTO_TCP, &number);
|
||||
printf("%u ports redirected (TCP) :", number);
|
||||
for(i = 0; i < number; i++)
|
||||
{
|
||||
printf(" %hu", port_list[i]);
|
||||
}
|
||||
printf("\n");
|
||||
free(port_list);
|
||||
}
|
||||
|
||||
void
|
||||
test_index(void)
|
||||
{
|
||||
char ifname[16/*IFNAMSIZ*/];
|
||||
char iaddr[32];
|
||||
char desc[64];
|
||||
char rhost[32];
|
||||
unsigned short iport = 0;
|
||||
unsigned short eport = 0;
|
||||
int proto = 0;
|
||||
unsigned int timestamp;
|
||||
ifname[0] = '\0';
|
||||
iaddr[0] = '\0';
|
||||
rhost[0] = '\0';
|
||||
if(get_redirect_rule_by_index(0, ifname, &eport, iaddr, sizeof(iaddr),
|
||||
&iport, &proto, desc, sizeof(desc),
|
||||
rhost, sizeof(rhost),
|
||||
×tamp, 0, 0) < 0)
|
||||
{
|
||||
printf("get.._by_index : no rule\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s %u -> %s:%u proto %d\n", ifname, (unsigned int)eport,
|
||||
iaddr, (unsigned int)iport, proto);
|
||||
printf("description: \"%s\"\n", desc);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int arc, char * * argv)
|
||||
{
|
||||
char buf[32];
|
||||
char desc[64];
|
||||
/*char rhost[32];*/
|
||||
unsigned short iport;
|
||||
unsigned int timestamp;
|
||||
u_int64_t packets = 0;
|
||||
u_int64_t bytes = 0;
|
||||
|
||||
openlog("testobsdrdr", LOG_PERROR, LOG_USER);
|
||||
if(init_redirect() < 0)
|
||||
{
|
||||
fprintf(stderr, "init_redirect() failed\n");
|
||||
return 1;
|
||||
}
|
||||
//add_redirect_rule("ep0", 12123, "192.168.1.23", 1234);
|
||||
//add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP);
|
||||
add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234,
|
||||
IPPROTO_UDP, "test description", 0);
|
||||
//add_redirect_rule2("em0", 12123, "127.1.2.3", 1234,
|
||||
// IPPROTO_TCP, "test description tcp");
|
||||
|
||||
list_rules();
|
||||
list_eports_tcp();
|
||||
|
||||
|
||||
if(get_redirect_rule("xl1", 4662, IPPROTO_TCP,
|
||||
buf, sizeof(buf), &iport, desc, sizeof(desc),
|
||||
×tamp,
|
||||
&packets, &bytes) < 0)
|
||||
printf("get_redirect_rule() failed\n");
|
||||
else
|
||||
{
|
||||
printf("\n%s:%d '%s' packets=%llu bytes=%llu\n", buf, (int)iport, desc,
|
||||
packets, bytes);
|
||||
}
|
||||
#if 0
|
||||
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
||||
printf("delete_redirect_rule() failed\n");
|
||||
else
|
||||
printf("delete_redirect_rule() succeded\n");
|
||||
|
||||
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
||||
printf("delete_redirect_rule() failed\n");
|
||||
else
|
||||
printf("delete_redirect_rule() succeded\n");
|
||||
#endif
|
||||
//test_index();
|
||||
|
||||
//clear_redirect_rules();
|
||||
//list_rules();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner and Thomas Bernard
|
||||
* (c) 2007 Darren Reed
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <kstat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include "../getifstats.h"
|
||||
|
||||
int
|
||||
getifstats(const char * ifname, struct ifdata * data)
|
||||
{
|
||||
char buffer[64], *s;
|
||||
kstat_named_t *kn;
|
||||
kstat_ctl_t *kc;
|
||||
int instance;
|
||||
kstat_t *ksp;
|
||||
uint32_t cnt32;
|
||||
void *ptr;
|
||||
|
||||
if (data == NULL)
|
||||
goto error;
|
||||
|
||||
if (ifname == NULL || *ifname == '\0')
|
||||
goto error;
|
||||
|
||||
s = (char *)ifname + strlen(ifname);
|
||||
s--;
|
||||
while ((s > ifname) && isdigit(*s))
|
||||
s--;
|
||||
|
||||
s++;
|
||||
instance = atoi(s);
|
||||
strlcpy(buffer, ifname, MIN(s - ifname + 1, 64));
|
||||
|
||||
kc = kstat_open();
|
||||
if (kc != NULL) {
|
||||
ksp = kstat_lookup(kc, buffer, instance, (char *)ifname);
|
||||
if (ksp && (kstat_read(kc, ksp, NULL) != -1)) {
|
||||
/* found the right interface */
|
||||
if (sizeof(long) == 8) {
|
||||
uint64_t cnt64;
|
||||
kn = kstat_data_lookup(ksp, "rbytes64");
|
||||
if (kn != NULL) {
|
||||
data->ibytes = kn->value.i64;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "ipackets64");
|
||||
if (kn != NULL) {
|
||||
data->ipackets = kn->value.i64;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "obytes64");
|
||||
if (kn != NULL) {
|
||||
data->obytes = kn->value.i64;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "opackets64");
|
||||
if (kn != NULL) {
|
||||
data->opackets = kn->value.i64;
|
||||
}
|
||||
} else {
|
||||
kn = kstat_data_lookup(ksp, "rbytes");
|
||||
if (kn != NULL) {
|
||||
data->ibytes = kn->value.i32;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "ipackets");
|
||||
if (kn != NULL) {
|
||||
data->ipackets = kn->value.i32;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "obytes");
|
||||
if (kn != NULL) {
|
||||
data->obytes = kn->value.i32;
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "opackets");
|
||||
if (kn != NULL) {
|
||||
data->ipackets = kn->value.i32;
|
||||
}
|
||||
}
|
||||
kn = kstat_data_lookup(ksp, "ifspeed");
|
||||
if (kn != NULL) {
|
||||
data->baudrate = kn->value.i32;
|
||||
}
|
||||
kstat_close(kc);
|
||||
return 0; /* ok */
|
||||
}
|
||||
syslog(LOG_ERR, "kstat_lookup/read() failed: %m");
|
||||
kstat_close(kc);
|
||||
return -1;
|
||||
} else {
|
||||
syslog(LOG_ERR, "kstat_open() failed: %m");
|
||||
}
|
||||
error:
|
||||
return -1; /* not found or error */
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* $Id: testgetifaddr.c,v 1.3 2011/04/11 10:41:57 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 <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include "getifaddr.h"
|
||||
|
||||
int main(int argc, char * * argv) {
|
||||
char addr[64];
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
openlog("testgetifaddr", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||
if(getifaddr(argv[1], addr, sizeof(addr)) < 0) {
|
||||
fprintf(stderr, "Cannot get address for interface %s.\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
printf("Interface %s has IP address %s.\n", argv[1], addr);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* $Id: testgetifstats.c,v 1.4 2007/02/07 22:14:47 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "getifstats.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
struct ifdata data;
|
||||
if(argc<2)
|
||||
{
|
||||
fprintf(stderr, "usage : %s <ifname>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
openlog("testgetifstats", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||
memset(&data, 0, sizeof(data));
|
||||
r = getifstats(argv[1], &data);
|
||||
printf("getifstats() returned %d\n", r);
|
||||
printf("stats for interface %s :\n", argv[1]);
|
||||
printf("bitrate = %lu\n", data.baudrate);
|
||||
printf(" input packets : %9lu\t input bytes : %9lu\n",
|
||||
data.ipackets, data.ibytes);
|
||||
printf("output packets : %9lu\toutput bytes : %9lu\n",
|
||||
data.opackets, data.obytes);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/* $Id: testupnpdescgen.c,v 1.25 2011/05/18 22:22: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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/* for mkdir */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "upnpdescgen.h"
|
||||
|
||||
char uuidvalue[] = "uuid:12345678-0000-0000-0000-00000000abcd";
|
||||
char serialnumber[] = "12345678";
|
||||
char modelnumber[] = "1";
|
||||
char presentationurl[] = "http://192.168.0.1:8080/";
|
||||
/*char presentationurl[] = "";*/
|
||||
|
||||
char * use_ext_ip_addr = NULL;
|
||||
const char * ext_if_name = "eth0";
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
int ipv6fc_firewall_enabled = 1;
|
||||
int ipv6fc_inbound_pinhole_allowed = 1;
|
||||
#endif
|
||||
|
||||
int getifaddr(const char * ifname, char * buf, int len)
|
||||
{
|
||||
strncpy(buf, "1.2.3.4", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int upnp_get_portmapping_number_of_entries(void)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int get_wan_connection_status(const char * ifname)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* To be improved */
|
||||
int
|
||||
xml_pretty_print(const char * s, int len, FILE * f)
|
||||
{
|
||||
int n = 0, i;
|
||||
int elt_close = 0;
|
||||
int c, indent = 0;
|
||||
if(!s)
|
||||
return n;
|
||||
while(len > 0)
|
||||
{
|
||||
c = *(s++); len--;
|
||||
switch(c)
|
||||
{
|
||||
case '<':
|
||||
if(len>0 && *s == '/')
|
||||
elt_close++;
|
||||
else if(len>0 && *s == '?')
|
||||
elt_close = 1;
|
||||
else
|
||||
elt_close = 0;
|
||||
if(elt_close!=1)
|
||||
{
|
||||
if(elt_close > 1)
|
||||
indent--;
|
||||
fputc('\n', f); n++;
|
||||
for(i=indent; i>0; i--)
|
||||
fputc(' ', f);
|
||||
n += indent;
|
||||
}
|
||||
fputc(c, f); n++;
|
||||
break;
|
||||
case '>':
|
||||
fputc(c, f); n++;
|
||||
if(elt_close==1)
|
||||
{
|
||||
/*fputc('\n', f); n++; */
|
||||
//elt_close = 0;
|
||||
if(indent > 0)
|
||||
indent--;
|
||||
}
|
||||
else if(elt_close == 0)
|
||||
indent++;
|
||||
break;
|
||||
case '\n':
|
||||
/* remove existing LF */
|
||||
break;
|
||||
default:
|
||||
fputc(c, f); n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* stupid test */
|
||||
const char * str1 = "Prefix123String";
|
||||
const char * str2 = "123String";
|
||||
|
||||
void stupid_test(void)
|
||||
{
|
||||
printf("str1:'%s' str2:'%s'\n", str1, str2);
|
||||
printf("str1:%p str2:%p str2-str1:%ld\n", str1, str2, (long)(str2-str1));
|
||||
}
|
||||
|
||||
/* main */
|
||||
|
||||
int
|
||||
main(int argc, char * * argv)
|
||||
{
|
||||
char * rootDesc;
|
||||
int rootDescLen;
|
||||
char * s;
|
||||
int l;
|
||||
FILE * f;
|
||||
|
||||
if(mkdir("testdescs", 0777) < 0) {
|
||||
if(errno != EEXIST) {
|
||||
perror("mkdir");
|
||||
}
|
||||
}
|
||||
printf("Root Description :\n");
|
||||
rootDesc = genRootDesc(&rootDescLen);
|
||||
xml_pretty_print(rootDesc, rootDescLen, stdout);
|
||||
f = fopen("testdescs/rootdesc.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(rootDesc, rootDescLen, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(rootDesc);
|
||||
printf("\n-------------\n");
|
||||
printf("WANIPConnection Description :\n");
|
||||
s = genWANIPCn(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
f = fopen("testdescs/wanipc_scpd.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(s, l, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
printf("WANConfig Description :\n");
|
||||
s = genWANCfg(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
f = fopen("testdescs/wanconfig_scpd.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(s, l, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
printf("Layer3Forwarding service :\n");
|
||||
s = genL3F(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
f = fopen("testdescs/l3f_scpd.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(s, l, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
printf("WANIPv6FirewallControl service :\n");
|
||||
s = gen6FC(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
f = fopen("testdescs/wanipv6fc_scpd.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(s, l, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
printf("DeviceProtection service :\n");
|
||||
s = genDP(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
f = fopen("testdescs/dp_scpd.xml", "w");
|
||||
if(f) {
|
||||
xml_pretty_print(s, l, f);
|
||||
fclose(f);
|
||||
}
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#endif
|
||||
#ifdef ENABLE_EVENTS
|
||||
s = getVarsWANIPCn(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
s = getVarsWANCfg(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
s = getVarsL3F(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
s = getVars6FC(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
s = getVarsDP(&l);
|
||||
xml_pretty_print(s, l, stdout);
|
||||
free(s);
|
||||
printf("\n-------------\n");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
stupid_test();
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* $Id: testupnppermissions.c,v 1.3 2009/09/14 15:24:46 nanard Exp $ */
|
||||
/* (c) 2007-2009 Thomas Bernard
|
||||
* MiniUPnP Project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "upnppermissions.h"
|
||||
|
||||
void
|
||||
print_upnpperm(const struct upnpperm * p)
|
||||
{
|
||||
switch(p->type)
|
||||
{
|
||||
case UPNPPERM_ALLOW:
|
||||
printf("allow ");
|
||||
break;
|
||||
case UPNPPERM_DENY:
|
||||
printf("deny ");
|
||||
break;
|
||||
default:
|
||||
printf("error ! ");
|
||||
}
|
||||
printf("%hu-%hu ", p->eport_min, p->eport_max);
|
||||
printf("%s/", inet_ntoa(p->address));
|
||||
printf("%s ", inet_ntoa(p->mask));
|
||||
printf("%hu-%hu", p->iport_min, p->iport_max);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int i, r;
|
||||
struct upnpperm p;
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Usage: %s \"permission line\" [...]\n", argv[0]);
|
||||
fprintf(stderr, "Example: %s \"allow 1234 10.10.10.10/32 1234\"\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
openlog("testupnppermissions", LOG_PERROR, LOG_USER);
|
||||
/* for(i=0; i<argc; i++)
|
||||
printf("%2d '%s'\n", i, argv[i]); */
|
||||
for(i=1; i<argc; i++) {
|
||||
printf("%2d '%s'\n", i, argv[i]);
|
||||
memset(&p, 0, sizeof(struct upnpperm));
|
||||
r = read_permission_line(&p, argv[i]);
|
||||
if(r==0) {
|
||||
printf("Permission read successfully\n");
|
||||
print_upnpperm(&p);
|
||||
} else {
|
||||
printf("Permission read failed, please check its correctness\n");
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
/* $Id: upnpdescgen.h,v 1.22 2011/05/18 22:22:24 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 __UPNPDESCGEN_H__
|
||||
#define __UPNPDESCGEN_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* for the root description
|
||||
* The child list reference is stored in "data" member using the
|
||||
* INITHELPER macro with index/nchild always in the
|
||||
* same order, whatever the endianness */
|
||||
struct XMLElt {
|
||||
const char * eltname; /* begin with '/' if no child */
|
||||
const char * data; /* Value */
|
||||
};
|
||||
|
||||
/* for service description */
|
||||
struct serviceDesc {
|
||||
const struct action * actionList;
|
||||
const struct stateVar * serviceStateTable;
|
||||
};
|
||||
|
||||
struct action {
|
||||
const char * name;
|
||||
const struct argument * args;
|
||||
};
|
||||
|
||||
struct argument { /* the name of the arg is obtained from the variable */
|
||||
unsigned char dir; /* MSB : don't append "New" Flag,
|
||||
* 5 Medium bits : magic argument name index
|
||||
* 2 LSB : 1 = in, 2 = out */
|
||||
unsigned char relatedVar; /* index of the related variable */
|
||||
};
|
||||
|
||||
struct stateVar {
|
||||
const char * name;
|
||||
unsigned char itype; /* MSB: sendEvent flag, 7 LSB: index in upnptypes */
|
||||
unsigned char idefault; /* default value */
|
||||
unsigned char iallowedlist; /* index in allowed values list
|
||||
* or in allowed range list */
|
||||
unsigned char ieventvalue; /* fixed value returned or magical values */
|
||||
};
|
||||
|
||||
/* little endian
|
||||
* The code has now be tested on big endian architecture */
|
||||
#define INITHELPER(i, n) ((char *)(((n)<<16)|(i)))
|
||||
|
||||
/* char * genRootDesc(int *);
|
||||
* returns: NULL on error, string allocated on the heap */
|
||||
char *
|
||||
genRootDesc(int * len);
|
||||
|
||||
/* for the two following functions */
|
||||
char *
|
||||
genWANIPCn(int * len);
|
||||
|
||||
char *
|
||||
genWANCfg(int * len);
|
||||
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
char *
|
||||
genL3F(int * len);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
char *
|
||||
gen6FC(int * len);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
char *
|
||||
genDP(int * len);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_EVENTS
|
||||
char *
|
||||
getVarsWANIPCn(int * len);
|
||||
|
||||
char *
|
||||
getVarsWANCfg(int * len);
|
||||
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
char *
|
||||
getVarsL3F(int * len);
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
char *
|
||||
getVars6FC(int * len);
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
char *
|
||||
getVarsDP(int * len);
|
||||
#endif
|
||||
#endif /* ENABLE_EVENTS */
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* $Id: upnpdescstrings.h,v 1.5 2007/02/09 10:12:52 nanard Exp $ */
|
||||
/* miniupnp project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006 Thomas Bernard
|
||||
* This software is subject to the coditions detailed in
|
||||
* the LICENCE file provided within the distribution */
|
||||
#ifndef __UPNPDESCSTRINGS_H__
|
||||
#define __UPNPDESCSTRINGS_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* strings used in the root device xml description */
|
||||
#define ROOTDEV_FRIENDLYNAME OS_NAME " router"
|
||||
#define ROOTDEV_MANUFACTURER OS_NAME
|
||||
#define ROOTDEV_MANUFACTURERURL OS_URL
|
||||
#define ROOTDEV_MODELNAME OS_NAME " router"
|
||||
#define ROOTDEV_MODELDESCRIPTION OS_NAME " router"
|
||||
#define ROOTDEV_MODELURL OS_URL
|
||||
|
||||
#define WANDEV_FRIENDLYNAME "WANDevice"
|
||||
#define WANDEV_MANUFACTURER "MiniUPnP"
|
||||
#define WANDEV_MANUFACTURERURL "http://miniupnp.free.fr/"
|
||||
#define WANDEV_MODELNAME "WAN Device"
|
||||
#define WANDEV_MODELDESCRIPTION "WAN Device"
|
||||
#define WANDEV_MODELNUMBER UPNP_VERSION
|
||||
#define WANDEV_MODELURL "http://miniupnp.free.fr/"
|
||||
#define WANDEV_UPC "MINIUPNPD"
|
||||
|
||||
#define WANCDEV_FRIENDLYNAME "WANConnectionDevice"
|
||||
#define WANCDEV_MANUFACTURER WANDEV_MANUFACTURER
|
||||
#define WANCDEV_MANUFACTURERURL WANDEV_MANUFACTURERURL
|
||||
#define WANCDEV_MODELNAME "MiniUPnPd"
|
||||
#define WANCDEV_MODELDESCRIPTION "MiniUPnP daemon"
|
||||
#define WANCDEV_MODELNUMBER UPNP_VERSION
|
||||
#define WANCDEV_MODELURL "http://miniupnp.free.fr/"
|
||||
#define WANCDEV_UPC "MINIUPNPD"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,536 @@
|
|||
/* $Id: upnpevents.c,v 1.17 2011/06/27 11:24:00 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2008-2011 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "upnpevents.h"
|
||||
#include "miniupnpdpath.h"
|
||||
#include "upnpglobalvars.h"
|
||||
#include "upnpdescgen.h"
|
||||
|
||||
#ifdef ENABLE_EVENTS
|
||||
/*enum subscriber_service_enum {
|
||||
EWanCFG = 1,
|
||||
EWanIPC,
|
||||
EL3F
|
||||
};*/
|
||||
|
||||
/* stuctures definitions */
|
||||
struct subscriber {
|
||||
LIST_ENTRY(subscriber) entries;
|
||||
struct upnp_event_notify * notify;
|
||||
time_t timeout;
|
||||
uint32_t seq;
|
||||
enum subscriber_service_enum service;
|
||||
char uuid[42];
|
||||
char callback[];
|
||||
};
|
||||
|
||||
struct upnp_event_notify {
|
||||
LIST_ENTRY(upnp_event_notify) entries;
|
||||
int s; /* socket */
|
||||
enum { ECreated=1,
|
||||
EConnecting,
|
||||
ESending,
|
||||
EWaitingForResponse,
|
||||
EFinished,
|
||||
EError } state;
|
||||
struct subscriber * sub;
|
||||
char * buffer;
|
||||
int buffersize;
|
||||
int tosend;
|
||||
int sent;
|
||||
const char * path;
|
||||
#ifdef ENABLE_IPV6
|
||||
int ipv6;
|
||||
char addrstr[48];
|
||||
#else
|
||||
char addrstr[16];
|
||||
#endif
|
||||
char portstr[8];
|
||||
};
|
||||
|
||||
/* prototypes */
|
||||
static void
|
||||
upnp_event_create_notify(struct subscriber * sub);
|
||||
|
||||
/* Subscriber list */
|
||||
LIST_HEAD(listhead, subscriber) subscriberlist = { NULL };
|
||||
|
||||
/* notify list */
|
||||
LIST_HEAD(listheadnotif, upnp_event_notify) notifylist = { NULL };
|
||||
|
||||
/* create a new subscriber */
|
||||
static struct subscriber *
|
||||
newSubscriber(const char * eventurl, const char * callback, int callbacklen)
|
||||
{
|
||||
struct subscriber * tmp;
|
||||
if(!eventurl || !callback || !callbacklen)
|
||||
return NULL;
|
||||
tmp = calloc(1, sizeof(struct subscriber)+callbacklen+1);
|
||||
if(!tmp)
|
||||
return NULL;
|
||||
if(strcmp(eventurl, WANCFG_EVENTURL)==0)
|
||||
tmp->service = EWanCFG;
|
||||
else if(strcmp(eventurl, WANIPC_EVENTURL)==0)
|
||||
tmp->service = EWanIPC;
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
else if(strcmp(eventurl, L3F_EVENTURL)==0)
|
||||
tmp->service = EL3F;
|
||||
#endif
|
||||
else {
|
||||
free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(tmp->callback, callback, callbacklen);
|
||||
tmp->callback[callbacklen] = '\0';
|
||||
/* make a dummy uuid */
|
||||
/* TODO: improve that */
|
||||
strncpy(tmp->uuid, uuidvalue, sizeof(tmp->uuid));
|
||||
tmp->uuid[sizeof(tmp->uuid)-1] = '\0';
|
||||
snprintf(tmp->uuid+37, 5, "%04lx", random() & 0xffff);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* creates a new subscriber and adds it to the subscriber list
|
||||
* also initiate 1st notify
|
||||
* TODO : add a check on the number of subscriber in order to
|
||||
* prevent memory overflow... */
|
||||
const char *
|
||||
upnpevents_addSubscriber(const char * eventurl,
|
||||
const char * callback, int callbacklen,
|
||||
int timeout)
|
||||
{
|
||||
struct subscriber * tmp;
|
||||
/*static char uuid[42];*/
|
||||
/* "uuid:00000000-0000-0000-0000-000000000000"; 5+36+1=42bytes */
|
||||
syslog(LOG_DEBUG, "addSubscriber(%s, %.*s, %d)",
|
||||
eventurl, callbacklen, callback, timeout);
|
||||
/*strncpy(uuid, uuidvalue, sizeof(uuid));
|
||||
uuid[sizeof(uuid)-1] = '\0';*/
|
||||
tmp = newSubscriber(eventurl, callback, callbacklen);
|
||||
if(!tmp)
|
||||
return NULL;
|
||||
if(timeout)
|
||||
tmp->timeout = time(NULL) + timeout;
|
||||
LIST_INSERT_HEAD(&subscriberlist, tmp, entries);
|
||||
upnp_event_create_notify(tmp);
|
||||
return tmp->uuid;
|
||||
}
|
||||
|
||||
/* renew a subscription (update the timeout) */
|
||||
int
|
||||
renewSubscription(const char * sid, int sidlen, int timeout)
|
||||
{
|
||||
struct subscriber * sub;
|
||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
||||
if(memcmp(sid, sub->uuid, 41) == 0) {
|
||||
sub->timeout = (timeout ? time(NULL) + timeout : 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
upnpevents_removeSubscriber(const char * sid, int sidlen)
|
||||
{
|
||||
struct subscriber * sub;
|
||||
if(!sid)
|
||||
return -1;
|
||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
||||
if(memcmp(sid, sub->uuid, 41) == 0) {
|
||||
if(sub->notify) {
|
||||
sub->notify->sub = NULL;
|
||||
}
|
||||
LIST_REMOVE(sub, entries);
|
||||
free(sub);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* notifies all subscriber of a number of port mapping change
|
||||
* or external ip address change */
|
||||
void
|
||||
upnp_event_var_change_notify(enum subscriber_service_enum service)
|
||||
{
|
||||
struct subscriber * sub;
|
||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
||||
if(sub->service == service && sub->notify == NULL)
|
||||
upnp_event_create_notify(sub);
|
||||
}
|
||||
}
|
||||
|
||||
/* create and add the notify object to the list */
|
||||
static void
|
||||
upnp_event_create_notify(struct subscriber * sub)
|
||||
{
|
||||
struct upnp_event_notify * obj;
|
||||
int flags;
|
||||
obj = calloc(1, sizeof(struct upnp_event_notify));
|
||||
if(!obj) {
|
||||
syslog(LOG_ERR, "%s: calloc(): %m", "upnp_event_create_notify");
|
||||
return;
|
||||
}
|
||||
obj->sub = sub;
|
||||
obj->state = ECreated;
|
||||
#ifdef ENABLE_IPV6
|
||||
obj->s = socket((obj->sub->callback[7] == '[') ? PF_INET6 : PF_INET,
|
||||
SOCK_STREAM, 0);
|
||||
#else
|
||||
obj->s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
#endif
|
||||
if(obj->s<0) {
|
||||
syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");
|
||||
goto error;
|
||||
}
|
||||
if((flags = fcntl(obj->s, F_GETFL, 0)) < 0) {
|
||||
syslog(LOG_ERR, "%s: fcntl(..F_GETFL..): %m",
|
||||
"upnp_event_create_notify");
|
||||
goto error;
|
||||
}
|
||||
if(fcntl(obj->s, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
syslog(LOG_ERR, "%s: fcntl(..F_SETFL..): %m",
|
||||
"upnp_event_create_notify");
|
||||
goto error;
|
||||
}
|
||||
if(sub)
|
||||
sub->notify = obj;
|
||||
LIST_INSERT_HEAD(¬ifylist, obj, entries);
|
||||
return;
|
||||
error:
|
||||
if(obj->s >= 0)
|
||||
close(obj->s);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
upnp_event_notify_connect(struct upnp_event_notify * obj)
|
||||
{
|
||||
int i;
|
||||
const char * p;
|
||||
unsigned short port;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_storage addr;
|
||||
#else
|
||||
struct sockaddr_in addr;
|
||||
#endif
|
||||
if(!obj)
|
||||
return;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
i = 0;
|
||||
if(obj->sub == NULL) {
|
||||
obj->state = EError;
|
||||
return;
|
||||
}
|
||||
p = obj->sub->callback;
|
||||
p += 7; /* http:// */
|
||||
#ifdef ENABLE_IPV6
|
||||
if(*p == '[') { /* ip v6 */
|
||||
p++;
|
||||
obj->ipv6 = 1;
|
||||
while(*p != ']' && i < (sizeof(obj->addrstr)-1))
|
||||
obj->addrstr[i++] = *(p++);
|
||||
if(*p == ']')
|
||||
p++;
|
||||
} else {
|
||||
#endif
|
||||
while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1))
|
||||
obj->addrstr[i++] = *(p++);
|
||||
#ifdef ENABLE_IPV6
|
||||
}
|
||||
#endif
|
||||
obj->addrstr[i] = '\0';
|
||||
if(*p == ':') {
|
||||
obj->portstr[0] = *p;
|
||||
i = 1;
|
||||
p++;
|
||||
port = (unsigned short)atoi(p);
|
||||
while(*p != '/') {
|
||||
if(i<7) obj->portstr[i++] = *p;
|
||||
p++;
|
||||
}
|
||||
obj->portstr[i] = 0;
|
||||
} else {
|
||||
port = 80;
|
||||
obj->portstr[0] = '\0';
|
||||
}
|
||||
obj->path = p;
|
||||
#ifdef ENABLE_IPV6
|
||||
if(obj->ipv6) {
|
||||
struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&addr;
|
||||
sa->sin6_family = AF_INET6;
|
||||
inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr));
|
||||
sa->sin6_port = htons(port);
|
||||
} else {
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&addr;
|
||||
sa->sin_family = AF_INET;
|
||||
inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr));
|
||||
sa->sin_port = htons(port);
|
||||
}
|
||||
#else
|
||||
addr.sin_family = AF_INET;
|
||||
inet_aton(obj->addrstr, &addr.sin_addr);
|
||||
addr.sin_port = htons(port);
|
||||
#endif
|
||||
syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",
|
||||
obj->addrstr, port, obj->path);
|
||||
obj->state = EConnecting;
|
||||
if(connect(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
if(errno != EINPROGRESS && errno != EWOULDBLOCK) {
|
||||
syslog(LOG_ERR, "%s: connect(): %m", "upnp_event_notify_connect");
|
||||
obj->state = EError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void upnp_event_prepare(struct upnp_event_notify * obj)
|
||||
{
|
||||
static const char notifymsg[] =
|
||||
"NOTIFY %s HTTP/1.1\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"NT: upnp:event\r\n"
|
||||
"NTS: upnp:propchange\r\n"
|
||||
"SID: %s\r\n"
|
||||
"SEQ: %u\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"\r\n"
|
||||
"%.*s\r\n";
|
||||
char * xml;
|
||||
int l;
|
||||
if(obj->sub == NULL) {
|
||||
obj->state = EError;
|
||||
return;
|
||||
}
|
||||
switch(obj->sub->service) {
|
||||
case EWanCFG:
|
||||
xml = getVarsWANCfg(&l);
|
||||
break;
|
||||
case EWanIPC:
|
||||
xml = getVarsWANIPCn(&l);
|
||||
break;
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
case EL3F:
|
||||
xml = getVarsL3F(&l);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
case E6FC:
|
||||
xml = getVars6FC(&l);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
case EDP:
|
||||
xml = getVarsDP(&l);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
xml = NULL;
|
||||
l = 0;
|
||||
}
|
||||
obj->buffersize = 1024;
|
||||
obj->buffer = malloc(obj->buffersize);
|
||||
/*if(!obj->buffer) {
|
||||
}*/
|
||||
obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg,
|
||||
obj->path, obj->addrstr, obj->portstr, l+2,
|
||||
obj->sub->uuid, obj->sub->seq,
|
||||
l, xml);
|
||||
if(xml) {
|
||||
free(xml);
|
||||
xml = NULL;
|
||||
}
|
||||
obj->state = ESending;
|
||||
}
|
||||
|
||||
static void upnp_event_send(struct upnp_event_notify * obj)
|
||||
{
|
||||
int i;
|
||||
syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s",
|
||||
"upnp_event_send", obj->addrstr, obj->portstr);
|
||||
syslog(LOG_DEBUG, "%s: msg: %s",
|
||||
"upnp_event_send", obj->buffer + obj->sent);
|
||||
i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
|
||||
if(i<0) {
|
||||
syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send");
|
||||
obj->state = EError;
|
||||
return;
|
||||
}
|
||||
else if(i != (obj->tosend - obj->sent))
|
||||
syslog(LOG_NOTICE, "%s: %d bytes send out of %d",
|
||||
"upnp_event_send", i, obj->tosend - obj->sent);
|
||||
obj->sent += i;
|
||||
if(obj->sent == obj->tosend)
|
||||
obj->state = EWaitingForResponse;
|
||||
}
|
||||
|
||||
static void upnp_event_recv(struct upnp_event_notify * obj)
|
||||
{
|
||||
int n;
|
||||
n = recv(obj->s, obj->buffer, obj->buffersize, 0);
|
||||
if(n<0) {
|
||||
syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv");
|
||||
obj->state = EError;
|
||||
return;
|
||||
}
|
||||
syslog(LOG_DEBUG, "%s: (%dbytes) %.*s", "upnp_event_recv",
|
||||
n, n, obj->buffer);
|
||||
obj->state = EFinished;
|
||||
if(obj->sub)
|
||||
obj->sub->seq++;
|
||||
}
|
||||
|
||||
static void
|
||||
upnp_event_process_notify(struct upnp_event_notify * obj)
|
||||
{
|
||||
switch(obj->state) {
|
||||
case EConnecting:
|
||||
/* now connected or failed to connect */
|
||||
upnp_event_prepare(obj);
|
||||
upnp_event_send(obj);
|
||||
break;
|
||||
case ESending:
|
||||
upnp_event_send(obj);
|
||||
break;
|
||||
case EWaitingForResponse:
|
||||
upnp_event_recv(obj);
|
||||
break;
|
||||
case EFinished:
|
||||
close(obj->s);
|
||||
obj->s = -1;
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "upnp_event_process_notify: unknown state");
|
||||
}
|
||||
}
|
||||
|
||||
void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd)
|
||||
{
|
||||
struct upnp_event_notify * obj;
|
||||
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
|
||||
syslog(LOG_DEBUG, "upnpevents_selectfds: %p %d %d",
|
||||
obj, obj->state, obj->s);
|
||||
if(obj->s >= 0) {
|
||||
switch(obj->state) {
|
||||
case ECreated:
|
||||
upnp_event_notify_connect(obj);
|
||||
if(obj->state != EConnecting)
|
||||
break;
|
||||
case EConnecting:
|
||||
case ESending:
|
||||
FD_SET(obj->s, writeset);
|
||||
if(obj->s > *max_fd)
|
||||
*max_fd = obj->s;
|
||||
break;
|
||||
case EWaitingForResponse:
|
||||
FD_SET(obj->s, readset);
|
||||
if(obj->s > *max_fd)
|
||||
*max_fd = obj->s;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void upnpevents_processfds(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
struct upnp_event_notify * obj;
|
||||
struct upnp_event_notify * next;
|
||||
struct subscriber * sub;
|
||||
struct subscriber * subnext;
|
||||
time_t curtime;
|
||||
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
|
||||
syslog(LOG_DEBUG, "%s: %p %d %d %d %d",
|
||||
"upnpevents_processfds", obj, obj->state, obj->s,
|
||||
FD_ISSET(obj->s, readset), FD_ISSET(obj->s, writeset));
|
||||
if(obj->s >= 0) {
|
||||
if(FD_ISSET(obj->s, readset) || FD_ISSET(obj->s, writeset))
|
||||
upnp_event_process_notify(obj);
|
||||
}
|
||||
}
|
||||
obj = notifylist.lh_first;
|
||||
while(obj != NULL) {
|
||||
next = obj->entries.le_next;
|
||||
if(obj->state == EError || obj->state == EFinished) {
|
||||
if(obj->s >= 0) {
|
||||
close(obj->s);
|
||||
}
|
||||
if(obj->sub)
|
||||
obj->sub->notify = NULL;
|
||||
/* remove also the subscriber from the list if there was an error */
|
||||
if(obj->state == EError && obj->sub) {
|
||||
LIST_REMOVE(obj->sub, entries);
|
||||
free(obj->sub);
|
||||
}
|
||||
if(obj->buffer) {
|
||||
free(obj->buffer);
|
||||
}
|
||||
LIST_REMOVE(obj, entries);
|
||||
free(obj);
|
||||
}
|
||||
obj = next;
|
||||
}
|
||||
/* remove timeouted subscribers */
|
||||
curtime = time(NULL);
|
||||
for(sub = subscriberlist.lh_first; sub != NULL; ) {
|
||||
subnext = sub->entries.le_next;
|
||||
if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) {
|
||||
LIST_REMOVE(sub, entries);
|
||||
free(sub);
|
||||
}
|
||||
sub = subnext;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_MINIUPNPDCTL
|
||||
void write_events_details(int s) {
|
||||
int n;
|
||||
char buff[80];
|
||||
struct upnp_event_notify * obj;
|
||||
struct subscriber * sub;
|
||||
write(s, "Events details :\n", 17);
|
||||
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
|
||||
n = snprintf(buff, sizeof(buff), " %p sub=%p state=%d s=%d\n",
|
||||
obj, obj->sub, obj->state, obj->s);
|
||||
write(s, buff, n);
|
||||
}
|
||||
write(s, "Subscribers :\n", 14);
|
||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
||||
n = snprintf(buff, sizeof(buff), " %p timeout=%d seq=%u service=%d\n",
|
||||
sub, (int)sub->timeout, sub->seq, sub->service);
|
||||
write(s, buff, n);
|
||||
n = snprintf(buff, sizeof(buff), " notify=%p %s\n",
|
||||
sub->notify, sub->uuid);
|
||||
write(s, buff, n);
|
||||
n = snprintf(buff, sizeof(buff), " %s\n",
|
||||
sub->callback);
|
||||
write(s, buff, n);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/* $Id: upnpevents.h,v 1.9 2011/05/18 22:21:19 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2008-2011 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef __UPNPEVENTS_H__
|
||||
#define __UPNPEVENTS_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_EVENTS
|
||||
enum subscriber_service_enum {
|
||||
EWanCFG = 1,
|
||||
EWanIPC,
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
EL3F,
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
E6FC,
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
EDP,
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
upnp_event_var_change_notify(enum subscriber_service_enum service);
|
||||
|
||||
const char *
|
||||
upnpevents_addSubscriber(const char * eventurl,
|
||||
const char * callback, int callbacklen,
|
||||
int timeout);
|
||||
|
||||
int
|
||||
upnpevents_removeSubscriber(const char * sid, int sidlen);
|
||||
|
||||
int
|
||||
renewSubscription(const char * sid, int sidlen, int timeout);
|
||||
|
||||
void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd);
|
||||
void upnpevents_processfds(fd_set *readset, fd_set *writeset);
|
||||
|
||||
#ifdef USE_MINIUPNPDCTL
|
||||
void write_events_details(int s);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
/* $Id: upnpglobalvars.c,v 1.25 2011/05/27 21:36:22 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2010 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "upnpglobalvars.h"
|
||||
|
||||
/* network interface for internet */
|
||||
const char * ext_if_name = 0;
|
||||
|
||||
/* file to store leases */
|
||||
#ifdef ENABLE_LEASEFILE
|
||||
const char* lease_file = 0;
|
||||
#endif
|
||||
|
||||
/* forced ip address to use for this interface
|
||||
* when NULL, getifaddr() is used */
|
||||
const char * use_ext_ip_addr = 0;
|
||||
|
||||
/* LAN address */
|
||||
/*const char * listen_addr = 0;*/
|
||||
|
||||
unsigned long downstream_bitrate = 0;
|
||||
unsigned long upstream_bitrate = 0;
|
||||
|
||||
/* startup time */
|
||||
time_t startup_time = 0;
|
||||
|
||||
int runtime_flags = 0;
|
||||
|
||||
const char * pidfilename = "/var/run/miniupnpd.pid";
|
||||
|
||||
char uuidvalue[] = "uuid:00000000-0000-0000-0000-000000000000";
|
||||
char serialnumber[SERIALNUMBER_MAX_LEN] = "00000000";
|
||||
|
||||
char modelnumber[MODELNUMBER_MAX_LEN] = "1";
|
||||
|
||||
/* presentation url :
|
||||
* http://nnn.nnn.nnn.nnn:ppppp/ => max 30 bytes including terminating 0 */
|
||||
char presentationurl[PRESENTATIONURL_MAX_LEN];
|
||||
|
||||
/* UPnP permission rules : */
|
||||
struct upnpperm * upnppermlist = 0;
|
||||
unsigned int num_upnpperm = 0;
|
||||
|
||||
#ifdef ENABLE_NATPMP
|
||||
/* NAT-PMP */
|
||||
#if 0
|
||||
unsigned int nextnatpmptoclean_timestamp = 0;
|
||||
unsigned short nextnatpmptoclean_eport = 0;
|
||||
unsigned short nextnatpmptoclean_proto = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||
unsigned int nextruletoclean_timestamp = 0;
|
||||
|
||||
#ifdef USE_PF
|
||||
const char * queue = 0;
|
||||
const char * tag = 0;
|
||||
#endif
|
||||
|
||||
#ifdef USE_NETFILTER
|
||||
/* chain name to use, both in the nat table
|
||||
* and the filter table */
|
||||
const char * miniupnpd_nat_chain = "MINIUPNPD";
|
||||
const char * miniupnpd_forward_chain = "MINIUPNPD";
|
||||
#endif
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
int nfqueue = -1;
|
||||
int n_nfqix = 0;
|
||||
unsigned nfqix[MAX_LAN_ADDR];
|
||||
#endif
|
||||
struct lan_addr_list lan_addrs;
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
/* ipv6 address used for HTTP */
|
||||
char ipv6_addr_for_http_with_brackets[64];
|
||||
#endif
|
||||
|
||||
/* Path of the Unix socket used to communicate with MiniSSDPd */
|
||||
const char * minissdpdsocketpath = "/var/run/minissdpd.sock";
|
||||
|
||||
/* BOOTID.UPNP.ORG and CONFIGID.UPNP.ORG */
|
||||
unsigned int upnp_bootid = 1;
|
||||
unsigned int upnp_configid = 1337;
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
int ipv6fc_firewall_enabled = 1;
|
||||
int ipv6fc_inbound_pinhole_allowed = 1;
|
||||
#endif
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/* $Id: upnpglobalvars.h,v 1.29 2011/05/27 21:36:22 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 __UPNPGLOBALVARS_H__
|
||||
#define __UPNPGLOBALVARS_H__
|
||||
|
||||
#include <time.h>
|
||||
#include "upnppermissions.h"
|
||||
#include "miniupnpdtypes.h"
|
||||
#include "config.h"
|
||||
|
||||
/* name of the network interface used to acces internet */
|
||||
extern const char * ext_if_name;
|
||||
|
||||
/* file to store all leases */
|
||||
#ifdef ENABLE_LEASEFILE
|
||||
extern const char * lease_file;
|
||||
#endif
|
||||
|
||||
/* forced ip address to use for this interface
|
||||
* when NULL, getifaddr() is used */
|
||||
extern const char * use_ext_ip_addr;
|
||||
|
||||
/* parameters to return to upnp client when asked */
|
||||
extern unsigned long downstream_bitrate;
|
||||
extern unsigned long upstream_bitrate;
|
||||
|
||||
/* statup time */
|
||||
extern time_t startup_time;
|
||||
|
||||
/* runtime boolean flags */
|
||||
extern int runtime_flags;
|
||||
#define LOGPACKETSMASK 0x0001
|
||||
#define SYSUPTIMEMASK 0x0002
|
||||
#ifdef ENABLE_NATPMP
|
||||
#define ENABLENATPMPMASK 0x0004
|
||||
#endif
|
||||
#define CHECKCLIENTIPMASK 0x0008
|
||||
#define SECUREMODEMASK 0x0010
|
||||
|
||||
#define ENABLEUPNPMASK 0x0020
|
||||
|
||||
#ifdef PF_ENABLE_FILTER_RULES
|
||||
#define PFNOQUICKRULESMASK 0x0040
|
||||
#endif
|
||||
|
||||
#define SETFLAG(mask) runtime_flags |= mask
|
||||
#define GETFLAG(mask) (runtime_flags & mask)
|
||||
#define CLEARFLAG(mask) runtime_flags &= ~mask
|
||||
|
||||
extern const char * pidfilename;
|
||||
|
||||
extern char uuidvalue[];
|
||||
|
||||
#define SERIALNUMBER_MAX_LEN (10)
|
||||
extern char serialnumber[];
|
||||
|
||||
#define MODELNUMBER_MAX_LEN (48)
|
||||
extern char modelnumber[];
|
||||
|
||||
#define PRESENTATIONURL_MAX_LEN (64)
|
||||
extern char presentationurl[];
|
||||
|
||||
/* UPnP permission rules : */
|
||||
extern struct upnpperm * upnppermlist;
|
||||
extern unsigned int num_upnpperm;
|
||||
|
||||
#ifdef ENABLE_NATPMP
|
||||
/* NAT-PMP */
|
||||
#if 0
|
||||
extern unsigned int nextnatpmptoclean_timestamp;
|
||||
extern unsigned short nextnatpmptoclean_eport;
|
||||
extern unsigned short nextnatpmptoclean_proto;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||
extern unsigned int nextruletoclean_timestamp;
|
||||
|
||||
#ifdef USE_PF
|
||||
/* queue and tag for PF rules */
|
||||
extern const char * queue;
|
||||
extern const char * tag;
|
||||
#endif
|
||||
|
||||
#ifdef USE_NETFILTER
|
||||
extern const char * miniupnpd_nat_chain;
|
||||
extern const char * miniupnpd_forward_chain;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
extern int nfqueue;
|
||||
extern int n_nfqix;
|
||||
extern unsigned nfqix[];
|
||||
#endif
|
||||
|
||||
/* lan addresses to listen to SSDP traffic */
|
||||
extern struct lan_addr_list lan_addrs;
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
/* ipv6 address used for HTTP */
|
||||
extern char ipv6_addr_for_http_with_brackets[64];
|
||||
#endif
|
||||
|
||||
extern const char * minissdpdsocketpath;
|
||||
|
||||
/* BOOTID.UPNP.ORG and CONFIGID.UPNP.ORG */
|
||||
extern unsigned int upnp_bootid;
|
||||
extern unsigned int upnp_configid;
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
extern int ipv6fc_firewall_enabled;
|
||||
extern int ipv6fc_inbound_pinhole_allowed;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,747 @@
|
|||
/* $Id: upnphttp.c,v 1.62 2011/08/26 12:46:14 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2011 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file included in this distribution.
|
||||
* */
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include <ctype.h>
|
||||
#include "config.h"
|
||||
#include "upnphttp.h"
|
||||
#include "upnpdescgen.h"
|
||||
#include "miniupnpdpath.h"
|
||||
#include "upnpsoap.h"
|
||||
#include "upnpevents.h"
|
||||
|
||||
struct upnphttp *
|
||||
New_upnphttp(int s)
|
||||
{
|
||||
struct upnphttp * ret;
|
||||
if(s<0)
|
||||
return NULL;
|
||||
ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
|
||||
if(ret == NULL)
|
||||
return NULL;
|
||||
memset(ret, 0, sizeof(struct upnphttp));
|
||||
ret->socket = s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
CloseSocket_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
if(close(h->socket) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "CloseSocket_upnphttp: close(%d): %m", h->socket);
|
||||
}
|
||||
h->socket = -1;
|
||||
h->state = 100;
|
||||
}
|
||||
|
||||
void
|
||||
Delete_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
if(h)
|
||||
{
|
||||
if(h->socket >= 0)
|
||||
CloseSocket_upnphttp(h);
|
||||
if(h->req_buf)
|
||||
free(h->req_buf);
|
||||
if(h->res_buf)
|
||||
free(h->res_buf);
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse HttpHeaders of the REQUEST */
|
||||
static void
|
||||
ParseHttpHeaders(struct upnphttp * h)
|
||||
{
|
||||
char * line;
|
||||
char * colon;
|
||||
char * p;
|
||||
int n;
|
||||
line = h->req_buf;
|
||||
/* TODO : check if req_buf, contentoff are ok */
|
||||
while(line < (h->req_buf + h->req_contentoff))
|
||||
{
|
||||
colon = strchr(line, ':');
|
||||
if(colon)
|
||||
{
|
||||
if(strncasecmp(line, "Content-Length", 14)==0)
|
||||
{
|
||||
p = colon;
|
||||
while(*p < '0' || *p > '9')
|
||||
p++;
|
||||
h->req_contentlen = atoi(p);
|
||||
/*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
|
||||
printf(" readbufflen=%d contentoff = %d\n",
|
||||
h->req_buflen, h->req_contentoff);*/
|
||||
}
|
||||
else if(strncasecmp(line, "SOAPAction", 10)==0)
|
||||
{
|
||||
p = colon;
|
||||
n = 0;
|
||||
while(*p == ':' || *p == ' ' || *p == '\t')
|
||||
p++;
|
||||
while(p[n]>=' ')
|
||||
{
|
||||
n++;
|
||||
}
|
||||
if((p[0] == '"' && p[n-1] == '"')
|
||||
|| (p[0] == '\'' && p[n-1] == '\''))
|
||||
{
|
||||
p++; n -= 2;
|
||||
}
|
||||
h->req_soapAction = p;
|
||||
h->req_soapActionLen = n;
|
||||
}
|
||||
#ifdef ENABLE_EVENTS
|
||||
else if(strncasecmp(line, "Callback", 8)==0)
|
||||
{
|
||||
p = colon;
|
||||
while(*p != '<' && *p != '\r' )
|
||||
p++;
|
||||
n = 0;
|
||||
while(p[n] != '>' && p[n] != '\r' )
|
||||
n++;
|
||||
h->req_Callback = p + 1;
|
||||
h->req_CallbackLen = MAX(0, n - 1);
|
||||
}
|
||||
else if(strncasecmp(line, "SID", 3)==0)
|
||||
{
|
||||
p = colon + 1;
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
n = 0;
|
||||
while(!isspace(p[n]))
|
||||
n++;
|
||||
h->req_SID = p;
|
||||
h->req_SIDLen = n;
|
||||
}
|
||||
/* Timeout: Seconds-nnnn */
|
||||
/* TIMEOUT
|
||||
Recommended. Requested duration until subscription expires,
|
||||
either number of seconds or infinite. Recommendation
|
||||
by a UPnP Forum working committee. Defined by UPnP vendor.
|
||||
Consists of the keyword "Second-" followed (without an
|
||||
intervening space) by either an integer or the keyword "infinite". */
|
||||
else if(strncasecmp(line, "Timeout", 7)==0)
|
||||
{
|
||||
p = colon + 1;
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(strncasecmp(p, "Second-", 7)==0) {
|
||||
h->req_Timeout = atoi(p+7);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while(!(line[0] == '\r' && line[1] == '\n'))
|
||||
line++;
|
||||
line += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* very minimalistic 404 error message */
|
||||
static void
|
||||
Send404(struct upnphttp * h)
|
||||
{
|
||||
/*
|
||||
static const char error404[] = "HTTP/1.1 404 Not found\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
|
||||
"<BODY><H1>Not Found</H1>The requested URL was not found"
|
||||
" on this server.</BODY></HTML>\r\n";
|
||||
int n;
|
||||
n = send(h->socket, error404, sizeof(error404) - 1, 0);
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Send404: send(http): %m");
|
||||
}*/
|
||||
static const char body404[] =
|
||||
"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
|
||||
"<BODY><H1>Not Found</H1>The requested URL was not found"
|
||||
" on this server.</BODY></HTML>\r\n";
|
||||
h->respflags = FLAG_HTML;
|
||||
BuildResp2_upnphttp(h, 404, "Not Found",
|
||||
body404, sizeof(body404) - 1);
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
|
||||
/* very minimalistic 501 error message */
|
||||
static void
|
||||
Send501(struct upnphttp * h)
|
||||
{
|
||||
/*
|
||||
static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
|
||||
"<BODY><H1>Not Implemented</H1>The HTTP Method "
|
||||
"is not implemented by this server.</BODY></HTML>\r\n";
|
||||
int n;
|
||||
n = send(h->socket, error501, sizeof(error501) - 1, 0);
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Send501: send(http): %m");
|
||||
}
|
||||
*/
|
||||
static const char body501[] =
|
||||
"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
|
||||
"<BODY><H1>Not Implemented</H1>The HTTP Method "
|
||||
"is not implemented by this server.</BODY></HTML>\r\n";
|
||||
h->respflags = FLAG_HTML;
|
||||
BuildResp2_upnphttp(h, 501, "Not Implemented",
|
||||
body501, sizeof(body501) - 1);
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
|
||||
static const char *
|
||||
findendheaders(const char * s, int len)
|
||||
{
|
||||
while(len-->0)
|
||||
{
|
||||
if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAS_DUMMY_SERVICE
|
||||
static void
|
||||
sendDummyDesc(struct upnphttp * h)
|
||||
{
|
||||
static const char xml_desc[] = "<?xml version=\"1.0\"?>\r\n"
|
||||
"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">"
|
||||
" <specVersion>"
|
||||
" <major>1</major>"
|
||||
" <minor>0</minor>"
|
||||
" </specVersion>"
|
||||
" <actionList />"
|
||||
" <serviceStateTable />"
|
||||
"</scpd>\r\n";
|
||||
BuildResp_upnphttp(h, xml_desc, sizeof(xml_desc)-1);
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sends the description generated by the parameter */
|
||||
static void
|
||||
sendXMLdesc(struct upnphttp * h, char * (f)(int *))
|
||||
{
|
||||
char * desc;
|
||||
int len;
|
||||
desc = f(&len);
|
||||
if(!desc)
|
||||
{
|
||||
static const char error500[] = "<HTML><HEAD><TITLE>Error 500</TITLE>"
|
||||
"</HEAD><BODY>Internal Server Error</BODY></HTML>\r\n";
|
||||
syslog(LOG_ERR, "Failed to generate XML description");
|
||||
h->respflags = FLAG_HTML;
|
||||
BuildResp2_upnphttp(h, 500, "Internal Server Error",
|
||||
error500, sizeof(error500)-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildResp_upnphttp(h, desc, len);
|
||||
}
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
/* ProcessHTTPPOST_upnphttp()
|
||||
* executes the SOAP query if it is possible */
|
||||
static void
|
||||
ProcessHTTPPOST_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
|
||||
{
|
||||
if(h->req_soapAction)
|
||||
{
|
||||
/* we can process the request */
|
||||
syslog(LOG_INFO, "SOAPAction: %.*s",
|
||||
h->req_soapActionLen, h->req_soapAction);
|
||||
ExecuteSoapAction(h,
|
||||
h->req_soapAction,
|
||||
h->req_soapActionLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char err400str[] =
|
||||
"<html><body>Bad request</body></html>";
|
||||
syslog(LOG_INFO, "No SOAPAction in HTTP headers");
|
||||
h->respflags = FLAG_HTML;
|
||||
BuildResp2_upnphttp(h, 400, "Bad Request",
|
||||
err400str, sizeof(err400str) - 1);
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* waiting for remaining data */
|
||||
h->state = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EVENTS
|
||||
/**
|
||||
* returns 0 if the callback header value is not valid
|
||||
* 1 if it is valid.
|
||||
*/
|
||||
static int
|
||||
checkCallbackURL(struct upnphttp * h)
|
||||
{
|
||||
char addrstr[48];
|
||||
int ipv6;
|
||||
const char * p;
|
||||
int i;
|
||||
|
||||
if(!h->req_Callback || h->req_CallbackLen < 8)
|
||||
return 0;
|
||||
if(memcmp(h->req_Callback, "http://", 7) != 0)
|
||||
return 0;
|
||||
ipv6 = 0;
|
||||
i = 0;
|
||||
p = h->req_Callback + 7;
|
||||
if(*p == '[') {
|
||||
p++;
|
||||
ipv6 = 1;
|
||||
while(*p != ']' && i < (sizeof(addrstr)-1)
|
||||
&& p < (h->req_Callback + h->req_CallbackLen))
|
||||
addrstr[i++] = *(p++);
|
||||
} else {
|
||||
while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1)
|
||||
&& p < (h->req_Callback + h->req_CallbackLen))
|
||||
addrstr[i++] = *(p++);
|
||||
}
|
||||
addrstr[i] = '\0';
|
||||
if(ipv6) {
|
||||
struct in6_addr addr;
|
||||
if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
|
||||
return 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
if(!h->ipv6
|
||||
|| (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
struct in_addr addr;
|
||||
if(inet_pton(AF_INET, addrstr, &addr) <= 0)
|
||||
return 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
if(h->ipv6) {
|
||||
if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
|
||||
return 0;
|
||||
if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
|
||||
return 0;
|
||||
} else {
|
||||
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
|
||||
{
|
||||
const char * sid;
|
||||
syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path);
|
||||
syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d",
|
||||
h->req_CallbackLen, h->req_Callback, h->req_Timeout);
|
||||
syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
|
||||
if(!h->req_Callback && !h->req_SID) {
|
||||
/* Missing or invalid CALLBACK : 412 Precondition Failed.
|
||||
* If CALLBACK header is missing or does not contain a valid HTTP URL,
|
||||
* the publisher must respond with HTTP error 412 Precondition Failed*/
|
||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
} else {
|
||||
/* - add to the subscriber list
|
||||
* - respond HTTP/x.x 200 OK
|
||||
* - Send the initial event message */
|
||||
/* Server:, SID:; Timeout: Second-(xx|infinite) */
|
||||
/* Check that the callback URL is on the same IP as
|
||||
* the request, and not on the internet, nor on ourself (DOS attack ?) */
|
||||
if(h->req_Callback) {
|
||||
if(checkCallbackURL(h)) {
|
||||
sid = upnpevents_addSubscriber(path, h->req_Callback,
|
||||
h->req_CallbackLen, h->req_Timeout);
|
||||
h->respflags = FLAG_TIMEOUT;
|
||||
if(sid) {
|
||||
syslog(LOG_DEBUG, "generated sid=%s", sid);
|
||||
h->respflags |= FLAG_SID;
|
||||
h->req_SID = sid;
|
||||
h->req_SIDLen = strlen(sid);
|
||||
}
|
||||
BuildResp_upnphttp(h, 0, 0);
|
||||
} else {
|
||||
syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s",
|
||||
h->req_CallbackLen, h->req_Callback);
|
||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||
}
|
||||
} else {
|
||||
/* subscription renew */
|
||||
/* Invalid SID
|
||||
412 Precondition Failed. If a SID does not correspond to a known,
|
||||
un-expired subscription, the publisher must respond
|
||||
with HTTP error 412 Precondition Failed. */
|
||||
if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) {
|
||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||
} else {
|
||||
h->respflags = FLAG_TIMEOUT;
|
||||
BuildResp_upnphttp(h, 0, 0);
|
||||
}
|
||||
}
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path)
|
||||
{
|
||||
syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path);
|
||||
syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
|
||||
/* Remove from the list */
|
||||
if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) {
|
||||
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
|
||||
} else {
|
||||
BuildResp_upnphttp(h, 0, 0);
|
||||
}
|
||||
SendResp_upnphttp(h);
|
||||
CloseSocket_upnphttp(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse and process Http Query
|
||||
* called once all the HTTP headers have been received. */
|
||||
static void
|
||||
ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
char HttpCommand[16];
|
||||
char HttpUrl[128];
|
||||
char * HttpVer;
|
||||
char * p;
|
||||
int i;
|
||||
p = h->req_buf;
|
||||
if(!p)
|
||||
return;
|
||||
for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
|
||||
HttpCommand[i] = *(p++);
|
||||
HttpCommand[i] = '\0';
|
||||
while(*p==' ')
|
||||
p++;
|
||||
for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
|
||||
HttpUrl[i] = *(p++);
|
||||
HttpUrl[i] = '\0';
|
||||
while(*p==' ')
|
||||
p++;
|
||||
HttpVer = h->HttpVer;
|
||||
for(i = 0; i<15 && *p != '\r'; i++)
|
||||
HttpVer[i] = *(p++);
|
||||
HttpVer[i] = '\0';
|
||||
syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
|
||||
HttpCommand, HttpUrl, HttpVer);
|
||||
ParseHttpHeaders(h);
|
||||
if(strcmp("POST", HttpCommand) == 0)
|
||||
{
|
||||
h->req_command = EPost;
|
||||
ProcessHTTPPOST_upnphttp(h);
|
||||
}
|
||||
else if(strcmp("GET", HttpCommand) == 0)
|
||||
{
|
||||
h->req_command = EGet;
|
||||
if(strcasecmp(ROOTDESC_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, genRootDesc);
|
||||
}
|
||||
else if(strcasecmp(WANIPC_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, genWANIPCn);
|
||||
}
|
||||
else if(strcasecmp(WANCFG_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, genWANCfg);
|
||||
}
|
||||
#ifdef HAS_DUMMY_SERVICE
|
||||
else if(strcasecmp(DUMMY_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendDummyDesc(h);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_L3F_SERVICE
|
||||
else if(strcasecmp(L3F_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, genL3F);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
else if(strcasecmp(WANIP6FC_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, gen6FC);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_DP_SERVICE
|
||||
else if(strcasecmp(DP_PATH, HttpUrl) == 0)
|
||||
{
|
||||
sendXMLdesc(h, genDP);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
|
||||
Send404(h);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_EVENTS
|
||||
else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
|
||||
{
|
||||
h->req_command = ESubscribe;
|
||||
ProcessHTTPSubscribe_upnphttp(h, HttpUrl);
|
||||
}
|
||||
else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
|
||||
{
|
||||
h->req_command = EUnSubscribe;
|
||||
ProcessHTTPUnSubscribe_upnphttp(h, HttpUrl);
|
||||
}
|
||||
#else
|
||||
else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
|
||||
{
|
||||
syslog(LOG_NOTICE, "SUBSCRIBE not implemented. ENABLE_EVENTS compile option disabled");
|
||||
Send501(h);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
|
||||
Send501(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Process_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
char buf[2048];
|
||||
int n;
|
||||
if(!h)
|
||||
return;
|
||||
switch(h->state)
|
||||
{
|
||||
case 0:
|
||||
n = recv(h->socket, buf, 2048, 0);
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "recv (state0): %m");
|
||||
h->state = 100;
|
||||
}
|
||||
else if(n==0)
|
||||
{
|
||||
syslog(LOG_WARNING, "HTTP Connection closed unexpectedly");
|
||||
h->state = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char * endheaders;
|
||||
/* if 1st arg of realloc() is null,
|
||||
* realloc behaves the same as malloc() */
|
||||
h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
|
||||
memcpy(h->req_buf + h->req_buflen, buf, n);
|
||||
h->req_buflen += n;
|
||||
h->req_buf[h->req_buflen] = '\0';
|
||||
/* search for the string "\r\n\r\n" */
|
||||
endheaders = findendheaders(h->req_buf, h->req_buflen);
|
||||
if(endheaders)
|
||||
{
|
||||
h->req_contentoff = endheaders - h->req_buf + 4;
|
||||
ProcessHttpQuery_upnphttp(h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
n = recv(h->socket, buf, 2048, 0);
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "recv (state1): %m");
|
||||
h->state = 100;
|
||||
}
|
||||
else if(n==0)
|
||||
{
|
||||
syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
|
||||
h->state = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*fwrite(buf, 1, n, stdout);*/ /* debug */
|
||||
h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
|
||||
memcpy(h->req_buf + h->req_buflen, buf, n);
|
||||
h->req_buflen += n;
|
||||
if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
|
||||
{
|
||||
ProcessHTTPPOST_upnphttp(h);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_WARNING, "Unexpected state: %d", h->state);
|
||||
}
|
||||
}
|
||||
|
||||
static const char httpresphead[] =
|
||||
"%s %d %s\r\n"
|
||||
/*"Content-Type: text/xml; charset=\"utf-8\"\r\n"*/
|
||||
"Content-Type: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Server: " MINIUPNPD_SERVER_STRING "\r\n"
|
||||
; /*"\r\n";*/
|
||||
/*
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<s:Body>"
|
||||
|
||||
"</s:Body>"
|
||||
"</s:Envelope>";
|
||||
*/
|
||||
/* with response code and response message
|
||||
* also allocate enough memory */
|
||||
|
||||
void
|
||||
BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
||||
const char * respmsg,
|
||||
int bodylen)
|
||||
{
|
||||
int templen;
|
||||
if(!h->res_buf)
|
||||
{
|
||||
templen = sizeof(httpresphead) + 128 + bodylen;
|
||||
h->res_buf = (char *)malloc(templen);
|
||||
if(!h->res_buf)
|
||||
{
|
||||
syslog(LOG_ERR, "malloc error in BuildHeader_upnphttp()");
|
||||
return;
|
||||
}
|
||||
h->res_buf_alloclen = templen;
|
||||
}
|
||||
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
|
||||
httpresphead, h->HttpVer,
|
||||
respcode, respmsg,
|
||||
(h->respflags&FLAG_HTML)?"text/html":"text/xml",
|
||||
bodylen);
|
||||
/* Additional headers */
|
||||
#ifdef ENABLE_EVENTS
|
||||
if(h->respflags & FLAG_TIMEOUT) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"Timeout: Second-");
|
||||
if(h->req_Timeout) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"%d\r\n", h->req_Timeout);
|
||||
} else {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"infinite\r\n");
|
||||
}
|
||||
}
|
||||
if(h->respflags & FLAG_SID) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"SID: %s\r\n", h->req_SID);
|
||||
}
|
||||
#endif
|
||||
h->res_buf[h->res_buflen++] = '\r';
|
||||
h->res_buf[h->res_buflen++] = '\n';
|
||||
if(h->res_buf_alloclen < (h->res_buflen + bodylen))
|
||||
{
|
||||
char * tmp;
|
||||
tmp = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
|
||||
if(tmp)
|
||||
{
|
||||
h->res_buf = tmp;
|
||||
h->res_buf_alloclen = h->res_buflen + bodylen;
|
||||
}
|
||||
else
|
||||
{
|
||||
syslog(LOG_ERR, "realloc error in BuildHeader_upnphttp()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BuildResp2_upnphttp(struct upnphttp * h, int respcode,
|
||||
const char * respmsg,
|
||||
const char * body, int bodylen)
|
||||
{
|
||||
BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
|
||||
if(body)
|
||||
memcpy(h->res_buf + h->res_buflen, body, bodylen);
|
||||
h->res_buflen += bodylen;
|
||||
}
|
||||
|
||||
/* responding 200 OK ! */
|
||||
void
|
||||
BuildResp_upnphttp(struct upnphttp * h,
|
||||
const char * body, int bodylen)
|
||||
{
|
||||
BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
|
||||
}
|
||||
|
||||
void
|
||||
SendResp_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
char * p;
|
||||
ssize_t n;
|
||||
size_t len;
|
||||
p = h->res_buf;
|
||||
len = h->res_buflen;
|
||||
while (len > 0)
|
||||
{
|
||||
n = send(h->socket, p, len, 0);
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "send(res_buf): %m");
|
||||
}
|
||||
else if(n == 0)
|
||||
{
|
||||
syslog(LOG_ERR, "send(res_buf): %zd bytes sent (out of %zu)",
|
||||
n, len);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += n;
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/* $Id: upnphttp.h,v 1.24 2011/06/27 11:06:00 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 __UPNPHTTP_H__
|
||||
#define __UPNPHTTP_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* server: HTTP header returned in all HTTP responses : */
|
||||
#define MINIUPNPD_SERVER_STRING OS_VERSION " UPnP/1.0 MiniUPnPd/" MINIUPNPD_VERSION
|
||||
|
||||
/*
|
||||
states :
|
||||
0 - waiting for data to read
|
||||
1 - waiting for HTTP Post Content.
|
||||
...
|
||||
>= 100 - to be deleted
|
||||
*/
|
||||
enum httpCommands {
|
||||
EUnknown = 0,
|
||||
EGet,
|
||||
EPost,
|
||||
ESubscribe,
|
||||
EUnSubscribe
|
||||
};
|
||||
|
||||
struct upnphttp {
|
||||
int socket;
|
||||
struct in_addr clientaddr; /* client address */
|
||||
#ifdef ENABLE_IPV6
|
||||
int ipv6;
|
||||
struct in6_addr clientaddr_v6;
|
||||
#endif
|
||||
int state;
|
||||
char HttpVer[16];
|
||||
/* request */
|
||||
char * req_buf;
|
||||
int req_buflen;
|
||||
int req_contentlen;
|
||||
int req_contentoff; /* header length */
|
||||
enum httpCommands req_command;
|
||||
const char * req_soapAction;
|
||||
int req_soapActionLen;
|
||||
#ifdef ENABLE_EVENTS
|
||||
const char * req_Callback; /* For SUBSCRIBE */
|
||||
int req_CallbackLen;
|
||||
int req_Timeout;
|
||||
const char * req_SID; /* For UNSUBSCRIBE */
|
||||
int req_SIDLen;
|
||||
#endif
|
||||
int respflags; /* see FLAG_* constants below */
|
||||
/* response */
|
||||
char * res_buf;
|
||||
int res_buflen;
|
||||
int res_buf_alloclen;
|
||||
/*int res_contentlen;*/
|
||||
/*int res_contentoff;*/ /* header length */
|
||||
LIST_ENTRY(upnphttp) entries;
|
||||
};
|
||||
|
||||
/* Include the "Timeout:" header in response */
|
||||
#define FLAG_TIMEOUT 0x01
|
||||
/* Include the "SID:" header in response */
|
||||
#define FLAG_SID 0x02
|
||||
|
||||
/* If set, the Content-Type is set to text/xml, otherwise it is text/xml */
|
||||
#define FLAG_HTML 0x80
|
||||
|
||||
/* New_upnphttp() */
|
||||
struct upnphttp *
|
||||
New_upnphttp(int);
|
||||
|
||||
/* CloseSocket_upnphttp() */
|
||||
void
|
||||
CloseSocket_upnphttp(struct upnphttp *);
|
||||
|
||||
/* Delete_upnphttp() */
|
||||
void
|
||||
Delete_upnphttp(struct upnphttp *);
|
||||
|
||||
/* Process_upnphttp() */
|
||||
void
|
||||
Process_upnphttp(struct upnphttp *);
|
||||
|
||||
/* BuildHeader_upnphttp()
|
||||
* build the header for the HTTP Response
|
||||
* also allocate the buffer for body data */
|
||||
void
|
||||
BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
||||
const char * respmsg,
|
||||
int bodylen);
|
||||
|
||||
/* BuildResp_upnphttp()
|
||||
* fill the res_buf buffer with the complete
|
||||
* HTTP 200 OK response from the body passed as argument */
|
||||
void
|
||||
BuildResp_upnphttp(struct upnphttp *, const char *, int);
|
||||
|
||||
/* BuildResp2_upnphttp()
|
||||
* same but with given response code/message */
|
||||
void
|
||||
BuildResp2_upnphttp(struct upnphttp * h, int respcode,
|
||||
const char * respmsg,
|
||||
const char * body, int bodylen);
|
||||
|
||||
/* SendResp_upnphttp() */
|
||||
void
|
||||
SendResp_upnphttp(struct upnphttp *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/* $Id: upnppermissions.c,v 1.14 2009/12/22 17:21:43 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 <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
#include "upnppermissions.h"
|
||||
|
||||
int
|
||||
read_permission_line(struct upnpperm * perm,
|
||||
char * p)
|
||||
{
|
||||
char * q;
|
||||
int n_bits;
|
||||
|
||||
/* first token: (allow|deny) */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(0 == memcmp(p, "allow", 5))
|
||||
{
|
||||
perm->type = UPNPPERM_ALLOW;
|
||||
p += 5;
|
||||
}
|
||||
else if(0 == memcmp(p, "deny", 4))
|
||||
{
|
||||
perm->type = UPNPPERM_DENY;
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* second token: eport or eport_min-eport_max */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p))
|
||||
return -1;
|
||||
for(q = p; isdigit(*q); q++);
|
||||
if(*q=='-')
|
||||
{
|
||||
*q = '\0';
|
||||
perm->eport_min = (u_short)atoi(p);
|
||||
q++;
|
||||
p = q;
|
||||
while(isdigit(*q))
|
||||
q++;
|
||||
*q = '\0';
|
||||
perm->eport_max = (u_short)atoi(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
*q = '\0';
|
||||
perm->eport_min = perm->eport_max = (u_short)atoi(p);
|
||||
}
|
||||
p = q + 1;
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
|
||||
/* third token: ip/mask */
|
||||
if(!isdigit(*p))
|
||||
return -1;
|
||||
for(q = p; isdigit(*q) || (*q == '.'); q++);
|
||||
if(*q=='/')
|
||||
{
|
||||
*q = '\0';
|
||||
if(!inet_aton(p, &perm->address))
|
||||
return -1;
|
||||
q++;
|
||||
p = q;
|
||||
while(isdigit(*q))
|
||||
q++;
|
||||
*q = '\0';
|
||||
n_bits = atoi(p);
|
||||
perm->mask.s_addr = htonl(n_bits ? (0xffffffff << (32 - n_bits)) : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*q = '\0';
|
||||
if(!inet_aton(p, &perm->address))
|
||||
return -1;
|
||||
perm->mask.s_addr = 0xffffffff;
|
||||
}
|
||||
p = q + 1;
|
||||
|
||||
/* fourth token: iport or iport_min-iport_max */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p))
|
||||
return -1;
|
||||
for(q = p; isdigit(*q); q++);
|
||||
if(*q=='-')
|
||||
{
|
||||
*q = '\0';
|
||||
perm->iport_min = (u_short)atoi(p);
|
||||
q++;
|
||||
p = q;
|
||||
while(isdigit(*q))
|
||||
q++;
|
||||
*q = '\0';
|
||||
perm->iport_max = (u_short)atoi(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
*q = '\0';
|
||||
perm->iport_min = perm->iport_max = (u_short)atoi(p);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("perm rule added : %s %hu-%hu %08x/%08x %hu-%hu\n",
|
||||
(perm->type==UPNPPERM_ALLOW)?"allow":"deny",
|
||||
perm->eport_min, perm->eport_max, ntohl(perm->address.s_addr),
|
||||
ntohl(perm->mask.s_addr), perm->iport_min, perm->iport_max);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_MINIUPNPDCTL
|
||||
void
|
||||
write_permlist(int fd, const struct upnpperm * permary,
|
||||
int nperms)
|
||||
{
|
||||
int l;
|
||||
const struct upnpperm * perm;
|
||||
int i;
|
||||
char buf[128];
|
||||
write(fd, "Permissions :\n", 14);
|
||||
for(i = 0; i<nperms; i++)
|
||||
{
|
||||
perm = permary + i;
|
||||
l = snprintf(buf, sizeof(buf), "%02d %s %hu-%hu %08x/%08x %hu-%hu\n",
|
||||
i,
|
||||
(perm->type==UPNPPERM_ALLOW)?"allow":"deny",
|
||||
perm->eport_min, perm->eport_max, ntohl(perm->address.s_addr),
|
||||
ntohl(perm->mask.s_addr), perm->iport_min, perm->iport_max);
|
||||
if(l<0)
|
||||
return;
|
||||
write(fd, buf, l);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* match_permission()
|
||||
* returns: 1 if eport, address, iport matches the permission rule
|
||||
* 0 if no match */
|
||||
static int
|
||||
match_permission(const struct upnpperm * perm,
|
||||
u_short eport, struct in_addr address, u_short iport)
|
||||
{
|
||||
if( (eport < perm->eport_min) || (perm->eport_max < eport))
|
||||
return 0;
|
||||
if( (iport < perm->iport_min) || (perm->iport_max < iport))
|
||||
return 0;
|
||||
if( (address.s_addr & perm->mask.s_addr)
|
||||
!= (perm->address.s_addr & perm->mask.s_addr) )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
check_upnp_rule_against_permissions(const struct upnpperm * permary,
|
||||
int n_perms,
|
||||
u_short eport, struct in_addr address,
|
||||
u_short iport)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<n_perms; i++)
|
||||
{
|
||||
if(match_permission(permary + i, eport, address, iport))
|
||||
{
|
||||
syslog(LOG_DEBUG,
|
||||
"UPnP permission rule %d matched : port mapping %s",
|
||||
i, (permary[i].type == UPNPPERM_ALLOW)?"accepted":"rejected"
|
||||
);
|
||||
return (permary[i].type == UPNPPERM_ALLOW);
|
||||
}
|
||||
}
|
||||
syslog(LOG_DEBUG, "no permission rule matched : accept by default (n_perms=%d)", n_perms);
|
||||
return 1; /* Default : accept */
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/* $Id: upnppermissions.h,v 1.7 2007/02/28 18:13:18 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 __UPNPPERMISSIONS_H__
|
||||
#define __UPNPPERMISSIONS_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include "config.h"
|
||||
|
||||
/* UPnP permission rule samples:
|
||||
* allow 1024-65535 192.168.3.0/24 1024-65535
|
||||
* deny 0-65535 192.168.1.125/32 0-65535 */
|
||||
struct upnpperm {
|
||||
enum {UPNPPERM_ALLOW=1, UPNPPERM_DENY=2 } type;
|
||||
/* is it an allow or deny permission rule ? */
|
||||
u_short eport_min, eport_max; /* external port range */
|
||||
struct in_addr address, mask; /* ip/mask */
|
||||
u_short iport_min, iport_max; /* internal port range */
|
||||
};
|
||||
|
||||
/* read_permission_line()
|
||||
* returns: 0 line read okay
|
||||
* -1 error reading line
|
||||
*
|
||||
* line sample :
|
||||
* allow 1024-65535 192.168.3.0/24 1024-65535
|
||||
* allow 22 192.168.4.33/32 22
|
||||
* deny 0-65535 0.0.0.0/0 0-65535 */
|
||||
int
|
||||
read_permission_line(struct upnpperm * perm,
|
||||
char * p);
|
||||
|
||||
/* check_upnp_rule_against_permissions()
|
||||
* returns: 0 if the upnp rule should be rejected,
|
||||
* 1 if it could be accepted */
|
||||
int
|
||||
check_upnp_rule_against_permissions(const struct upnpperm * permary,
|
||||
int n_perms,
|
||||
u_short eport, struct in_addr address,
|
||||
u_short iport);
|
||||
|
||||
#ifdef USE_MINIUPNPDCTL
|
||||
void
|
||||
write_permlist(int fd, const struct upnpperm * permary,
|
||||
int nperms);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,173 @@
|
|||
/* $Id: upnpredirect.h,v 1.24 2011/06/22 20:34:39 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 __UPNPREDIRECT_H__
|
||||
#define __UPNPREDIRECT_H__
|
||||
|
||||
/* for u_int64_t */
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_LEASEFILE
|
||||
int reload_from_lease_file(void);
|
||||
#endif
|
||||
|
||||
/* upnp_redirect()
|
||||
* calls OS/fw dependant implementation of the redirection.
|
||||
* protocol should be the string "TCP" or "UDP"
|
||||
* returns: 0 on success
|
||||
* -1 failed to redirect
|
||||
* -2 already redirected
|
||||
* -3 permission check failed
|
||||
*/
|
||||
int
|
||||
upnp_redirect(const char * rhost, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * protocol, const char * desc,
|
||||
unsigned int leaseduration);
|
||||
|
||||
/* upnp_redirect_internal()
|
||||
* same as upnp_redirect() without any check */
|
||||
int
|
||||
upnp_redirect_internal(const char * rhost, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
int proto, const char * desc,
|
||||
unsigned int timestamp);
|
||||
|
||||
/* upnp_get_redirection_infos()
|
||||
* returns : 0 on success
|
||||
* -1 failed to get the port mapping entry or no entry exists */
|
||||
int
|
||||
upnp_get_redirection_infos(unsigned short eport, const char * protocol,
|
||||
unsigned short * iport, char * iaddr, int iaddrlen,
|
||||
char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * leaseduration);
|
||||
|
||||
/* upnp_get_redirection_infos_by_index()
|
||||
* returns : 0 on success
|
||||
* -1 failed to get the port mapping or index out of range */
|
||||
int
|
||||
upnp_get_redirection_infos_by_index(int index,
|
||||
unsigned short * eport, char * protocol,
|
||||
unsigned short * iport,
|
||||
char * iaddr, int iaddrlen,
|
||||
char * desc, int desclen,
|
||||
char * rhost, int rhostlen,
|
||||
unsigned int * leaseduration);
|
||||
|
||||
/* upnp_delete_redirection()
|
||||
* returns: 0 on success
|
||||
* -1 on failure*/
|
||||
int
|
||||
upnp_delete_redirection(unsigned short eport, const char * protocol);
|
||||
|
||||
/* _upnp_delete_redir()
|
||||
* same as above */
|
||||
int
|
||||
_upnp_delete_redir(unsigned short eport, int proto);
|
||||
|
||||
/* Periodic cleanup functions
|
||||
*/
|
||||
struct rule_state
|
||||
{
|
||||
u_int64_t packets;
|
||||
u_int64_t bytes;
|
||||
struct rule_state * next;
|
||||
unsigned short eport;
|
||||
unsigned char proto;
|
||||
unsigned char to_remove;
|
||||
};
|
||||
|
||||
/* return a linked list of all rules
|
||||
* or an empty list if there are not enough
|
||||
* As a "side effect", delete rules which are expired */
|
||||
struct rule_state *
|
||||
get_upnp_rules_state_list(int max_rules_number_target);
|
||||
|
||||
/* return the number of port mapping entries */
|
||||
int
|
||||
upnp_get_portmapping_number_of_entries(void);
|
||||
|
||||
/* remove_unused_rules() :
|
||||
* also free the list */
|
||||
void
|
||||
remove_unused_rules(struct rule_state * list);
|
||||
|
||||
/* upnp_get_portmappings_in_range()
|
||||
* return a list of all "external" ports for which a port
|
||||
* mapping exists */
|
||||
unsigned short *
|
||||
upnp_get_portmappings_in_range(unsigned short startport,
|
||||
unsigned short endport,
|
||||
const char * protocol,
|
||||
unsigned int * number);
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
/* function to be used by WANIPv6_FirewallControl implementation */
|
||||
|
||||
/* retreive outbound pinhole timeout*/
|
||||
int
|
||||
upnp_check_outbound_pinhole(int proto, int * timeout);
|
||||
|
||||
/* add an inbound pinehole
|
||||
* return value :
|
||||
* 1 = success
|
||||
* -1 = Pinhole space exhausted
|
||||
* .. = error */
|
||||
int
|
||||
upnp_add_inboundpinhole(const char * raddr, unsigned short rport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * protocol, const char * leaseTime, int * uid);
|
||||
|
||||
int
|
||||
upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * proto, int * uid);
|
||||
|
||||
/*
|
||||
* return values :
|
||||
* -4 not found
|
||||
* -5 in another table
|
||||
* -6 in another chain
|
||||
* -7 in a chain but not a rule. (chain policy)
|
||||
* */
|
||||
int
|
||||
upnp_get_pinhole_info(const char * raddr, unsigned short rport, char * iaddr, unsigned short * iport, char * proto, const char * uid, char * lt);
|
||||
|
||||
/* update the lease time */
|
||||
int
|
||||
upnp_update_inboundpinhole(const char * uid, const char * leasetime);
|
||||
|
||||
/* remove the inbound pinhole */
|
||||
int
|
||||
upnp_delete_inboundpinhole(const char * uid);
|
||||
|
||||
/* ... */
|
||||
int
|
||||
upnp_check_pinhole_working(const char * uid, char * eaddr, char * iaddr, unsigned short * eport, unsigned short * iport, char * protocol, int * rulenum_used);
|
||||
|
||||
/* number of packets that went through the pinhole */
|
||||
int
|
||||
upnp_get_pinhole_packets(const char * uid, int * packets);
|
||||
|
||||
/* ? */
|
||||
int
|
||||
upnp_clean_expiredpinhole(void);
|
||||
|
||||
#endif /* ENABLE_6FC_SERVICE */
|
||||
|
||||
/* stuff for responding to miniupnpdctl */
|
||||
#ifdef USE_MINIUPNPDCTL
|
||||
void
|
||||
write_ruleset_details(int s);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/* $Id: upnpreplyparse.c,v 1.11 2011/02/07 16:17: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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
static void
|
||||
NameValueParserStartElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
if(l>63)
|
||||
l = 63;
|
||||
memcpy(data->curelt, name, l);
|
||||
data->curelt[l] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserGetData(void * d, const char * datas, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||
{
|
||||
/* specific case for NewPortListing which is a XML Document */
|
||||
data->portListing = malloc(l + 1);
|
||||
if(!data->portListing)
|
||||
{
|
||||
/* malloc error */
|
||||
return;
|
||||
}
|
||||
memcpy(data->portListing, datas, l);
|
||||
data->portListing[l] = '\0';
|
||||
data->portListingLength = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* standard case. Limited to 63 chars strings */
|
||||
nv = malloc(sizeof(struct NameValue));
|
||||
if(l>63)
|
||||
l = 63;
|
||||
strncpy(nv->name, data->curelt, 64);
|
||||
nv->name[63] = '\0';
|
||||
memcpy(nv->value, datas, l);
|
||||
nv->value[l] = '\0';
|
||||
LIST_INSERT_HEAD( &(data->head), nv, entries);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
LIST_INIT(&(data->head));
|
||||
data->portListing = NULL;
|
||||
data->portListingLength = 0;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = 0;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
if(pdata->portListing)
|
||||
{
|
||||
free(pdata->portListing);
|
||||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->head.lh_first) != NULL)
|
||||
{
|
||||
LIST_REMOVE(nv, entries);
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->head.lh_first;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
if(strcmp(nv->name, Name) == 0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* useless now that minixml ignores namespaces by itself */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
char * pname;
|
||||
for(nv = pdata->head.lh_first;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
pname = strrchr(nv->name, ':');
|
||||
if(pname)
|
||||
pname++;
|
||||
else
|
||||
pname = nv->name;
|
||||
if(strcmp(pname, Name)==0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.head.lh_first;
|
||||
nv != NULL;
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/* $Id: upnpreplyparse.h,v 1.11 2011/02/07 16:17: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 */
|
||||
|
||||
#ifndef __UPNPREPLYPARSE_H__
|
||||
#define __UPNPREPLYPARSE_H__
|
||||
|
||||
#if defined(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__)
|
||||
#include "bsdqueue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
LIST_ENTRY(NameValue) entries;
|
||||
char name[64];
|
||||
char value[64];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
LIST_HEAD(listhead, NameValue) head;
|
||||
char curelt[64];
|
||||
char * portListing;
|
||||
int portListingLength;
|
||||
};
|
||||
|
||||
/* ParseNameValue() */
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data);
|
||||
|
||||
/* ClearNameValueList() */
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata);
|
||||
|
||||
/* GetValueFromNameValueList() */
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
|
||||
/* GetValueFromNameValueListIgnoreNS() */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
|
||||
/* DisplayNameValueList() */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
/* $Id: upnpsoap.h,v 1.8 2007/02/07 22:16:19 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 __UPNPSOAP_H__
|
||||
#define __UPNPSOAP_H__
|
||||
|
||||
/* ExecuteSoapAction():
|
||||
* this method executes the requested Soap Action */
|
||||
void
|
||||
ExecuteSoapAction(struct upnphttp *, const char *, int);
|
||||
|
||||
/* SoapError():
|
||||
* sends a correct SOAP error with an UPNPError code and
|
||||
* description */
|
||||
void
|
||||
SoapError(struct upnphttp * h, int errCode, const char * errDesc);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* $Id: upnpurns.h,v 1.1 2011/05/13 15:32:53 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 __UPNPURNS_H__
|
||||
#define __UPNPURNS_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef IGD_V2
|
||||
/* IGD v2 */
|
||||
#define DEVICE_TYPE_IGD "urn:schemas-upnp-org:device:InternetGatewayDevice:2"
|
||||
#define DEVICE_TYPE_WAN "urn:schemas-upnp-org:device:WANDevice:2"
|
||||
#define DEVICE_TYPE_WANC "urn:schemas-upnp-org:device:WANConnectionDevice:2"
|
||||
#define SERVICE_TYPE_WANIPC "urn:schemas-upnp-org:service:WANIPConnection:2"
|
||||
#define SERVICE_ID_WANIPC "urn:upnp-org:serviceId:WANIPConn1"
|
||||
#else
|
||||
/* IGD v1 */
|
||||
#define DEVICE_TYPE_IGD "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
||||
#define DEVICE_TYPE_WAN "urn:schemas-upnp-org:device:WANDevice:1"
|
||||
#define DEVICE_TYPE_WANC "urn:schemas-upnp-org:device:WANConnectionDevice:1"
|
||||
#define SERVICE_TYPE_WANIPC "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
#define SERVICE_ID_WANIPC "urn:upnp-org:serviceId:WANIPConn1"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue