Tanks for all your hints, finally I've found a quite fitting solution for my use case - including the Raspberry PI!
The used router is - as I've already mentioned - a FritzBox. This is a quite powerful device also, and there is a quite good support community for that. I also wrote already, that the FritzBox is in general able to trace the entire traffic into a Wireshark file, but this is only possible via the Web-Interface.
But: There are resourceful people out there, who know how to tweak this device and know alternative - not officially documented - means to access features of the router.
The keyword for that is "fritzcap", means
capture for the
fritzbox. If you google for it, you find the
native implementation here (mostly in German) and - what is very interessting for me - the
python porting hosted by Google. This port is not so powerful, at least according to the documentation, but my use case is a very simple one and fits perfectly to the Raspberry Pi, as python is a standard tool for it and also easy to modify.
Fritzcap is running on a computer within the network, we can use a Raspberry for it which is directly connected to the LAN-Port of the FritzBox. The script accesses the FritzBox just with a special URL which lead the FritzBox to respond with the wanted trace data. This data is simply captured by the script and stored to the local Raspberry Pi user filesystem.
As the original python script does more than needed for my task and needs a user interaction (press key button) and a filing which is not suitable for me, I've modified the script accordingly. You can find my modified version below.
If you want to use it, please download all python files from the mentioned
Google-Server above, because the script still needs the external libraries provided with fritzcap.
My traffic capture is now running 24/7, using my first Raspberry Pi!!! Great!
Code: Select all
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
#################################################################################
# Simple FritzCap python port
# Simplifies generation and examination of traces taken from AVM FritzBox and/or SpeedPort
# Traces can be examined using WireShark
# (c) neil.young 2010 (spongebob.squarepants in http://www.ip-phone-forum.de/)
# based on the Windows GUI exe with same name
##################################################################################
# Copyright (c) 2010, neil.young
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the <organization> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
##################################################################################
import urllib, re, hashlib, sys, datetime, os, locale, time
script_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(script_dir + '/core')
from tracer import Tracer
from pcap_parse import PcapParser
from g711_decoder import G711Decoder
# Configuration (just change here) ###############################################
boxname = 'xxx.xxx.xx.xx' # ip of the router
password = 'yyyyyyyyyyyyyyyyy' # your password, adapt
protocol = 'https' # or http
capfolder = 'captures' # plus subfolders according to day, month, year, hour, minute
pre_05_50 = False # for versions < FRITZ!OS 05.50
capture_seconds = 60*60 # capture data for x seconds each
locale.setlocale(locale.LC_ALL,'de_DE.UTF-8') # set your locale
##################################################################################
# Commands
default_login = 'getpage=../html/de/menus/menu2.html&errorpage=../html/index.html&var:lang=de&var:pagename=home&var:menu=home&=&login:command/password=%s'
if pre_05_50:
sid_challenge = protocol + '://' + boxname + '/cgi-bin/webcm?getpage=../html/login_sid.xml'
sid_login_url = protocol + '://' + boxname + '/cgi-bin/webcm'
sid_login_parm = 'login:command/response=%s&getpage=../html/login_sid.xml'
else:
sid_challenge = protocol + '://' + boxname + '/login_sid.lua'
sid_login_url = sid_challenge
sid_login_parm = 'response=%s&page=&username='
start = '?start=1&start1=Start'
stop = '?stop=1&stop1=Stop'
# Main
def main():
global capfile
SID = '' # Required later
while True: # Run endless
print " "
try:
# Try to get a session id SID
sid = urllib.urlopen(sid_challenge)
if sid.getcode() == 200:
# Read and parse the response in order to get the challenge (not a full blown xml parser)
challenge = re.search('<Challenge>(.*?)</Challenge>', sid.read()).group(1)
# Create a UTF-16LE string from challenge + '-' + password, non ISO-8859-1 characters will except here (e.g. EUR)
challenge_bf = (challenge + '-' + password).decode('iso-8859-1').encode('utf-16le')
# Calculate the MD5 hash
m = hashlib.md5()
m.update(challenge_bf)
# Make a byte response string from challenge + '-' + md5_hex_value
response_bf = challenge + '-' + m.hexdigest().lower()
# Answer the challenge
login = urllib.urlopen(sid_login_url, sid_login_parm % response_bf)
if login.getcode() == 200:
SID = re.search('<SID>(.*?)</SID>', login.read()).group(1);
print "Login OK, SID=%s" % SID
else:
print "Could not login"
return
else:
print 'Wrong SID code...'
# end of if sid.getcode() == 200
except:
print 'Legacy login...'
# Legacy login
command = urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/webcm', default_login % password)
response = command.read()
# Right now I don't know how to check the result of a login operation. So I just search for the errorMessage
if command.getcode() == 200:
try:
result = urllib.unquote(re.search('<p class="errorMessage">(.*?)</p>', response).group(1).decode('iso-8859-1')).replace(" "," ")
except:
result = ''
print 'Login attempt was made. %s' % result
# end of try/except:
# Create capfile folders
folder = script_dir + '/' + capfolder + '/' + datetime.datetime.now().strftime('%Y') + '/' + datetime.datetime.now().strftime('%m_%B') + '/' + datetime.datetime.now().strftime('%d_%A')
if not os.path.exists(folder):
os.makedirs(folder)
capfile = folder + '/capture_' + (datetime.datetime.now().strftime('%H%M')) + 'Uhr.eth'
# Start tracer thread, wait for given number of seconds...
if SID != '':
Tracer(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + start + "&sid=%s" % SID, capfile).start()
else:
Tracer(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + start, capfile).start()
print 'Trace started at %s o\'clock, capture for %d minutes...' % ((datetime.datetime.now().strftime('%H:%M')), capture_seconds/60)
time.sleep(capture_seconds)
# Clean stop
print 'Stopping trace'
if SID != '':
urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + stop + "&sid=%s" % SID)
else:
urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + stop)
print 'Capture done'
# end of while True
print 'All done'
if __name__ == '__main__':
main()
As the script is running in an endless loop, I've added some small bash scripts for the Raspberry Pi which can be used for manual start and stop of the script and a restart script for usage e.g. in a cronjob. These bash-scripts
need to reside in the same directory as the python script.
Start the script:
Code: Select all
#!/bin/bash
python $(dirname $0)/fritzcap.py &
Stop the script:
Code: Select all
#!/bin/bash
process_output=$(ps aux | grep "fritzcap.*\.py" | grep -v grep)
if [ -n "$process_output" ]; then
echo
echo 'This is the fritzcap process:'
echo $process_output
process_pid=$(echo $process_output|awk '{print $2}')
echo "Kill the fritzcap-script with process id $process_pid..."
kill $process_pid
else
echo 'Process fritzcap.py not found for killing.'
fi
Restart the script:
Code: Select all
#!/bin/bash
$(dirname $0)/stop_fritzcap.sh
echo
echo Wait for 10 seconds before restarting fritzcap...
sleep 10
$(dirname $0)/start_fritzcap.sh
Have fun!