Python Forum
Need someone to help me edit this script
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Need someone to help me edit this script
#1
I found a script that will send SIP messages to devices. It uses a template to setup the info to be sent. The template is this
NOTIFY sip:unknown@%(dest_ip)s SIP/2.0
Via: SIP/2.0/UDP %(source_ip)s:%(source_port)s;branch=z9hG4bK001b84f6;rport
Max-Forwards: 70
From: "Nimbus" <sip:Nimbus@%(source_ip)s>;tag=as2e95fad1
To: <sip:unknown@%(dest_ip)s:%(dest_port)s>
Contact: <sip:Nimbus@%(source_ip)s:%(source_port)s>
Call-ID: Nimbus@%(source_ip)s
Event: check-sync
User-Agent: Nimbus
Subscription-State: terminated
Supported: replaces,timer,check-sync
Allow-Events: ua-profile, check-sync
Content-Type: application/url

%(body)s


The python code I am using is this:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# -*- Mode: Python -*-
#
# 
# This program is available under the Lesser General Public Licence (LGPL) Version 3
# This software is released for didactical and debugging purposes. You're free to use it at your own risk.

import socket
import time
import sys
import optparse
import select
import cStringIO
import re

from string import Template


def_request = """OPTIONS sip:%(dest_ip)s:%(dest_port)s SIP/2.0
Via: SIP/2.0/UDP %(source_ip)s:%(source_port)s
Max-Forwards: 70
From: "fake" <sip:fake@%(source_ip)s>
To: <sip:%(dest_ip)s:%(dest_port)s>
Contact: <sip:fake@%(source_ip)s:%(source_port)s>
Call-ID: fake-id@%(source_ip)s
User-Agent: SIPPing
Date: Wed, 24 Apr 2013 20:35:23 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer"""


def_out = ""


class CustomTemplate(Template):
    idpattern = r'[a-z][\.\-_a-z0-9]*'


class SipError(Exception):
    pass


class SipUnpackError(SipError):
    pass


class SipNeedData(SipUnpackError):
    pass


class SipPackError(SipError):
    pass


def canon_header(s):
    exception = {
        'call-id': 'Call-ID',
        'cseq': 'CSeq',
        'www-authenticate': 'WWW-Authenticate'
    }
    short = ['allow-events', 'u', 'call-id', 'i', 'contact', 'm', 'content-encoding', 'e',
        'content-length', 'l', 'content-type', 'c', 'event', 'o', 'from', 'f', 'subject', 's', 'supported', 'k', 'to', 't', 'via', 'v']
    s = s.lower()
    return ((len(s) == 1) and s in short and canon_header(short[short.index(s) - 1])) \
        or (s in exception and exception[s]) or '-'.join([x.capitalize() for x in s.split('-')])


def parse_headers(f):
        """Return dict of HTTP headers parsed from a file object."""
        d = {}
        while 1:
            line = f.readline().strip()
            if not line:
                break
            l = line.split(None, 1)
            if not l[0].endswith(':'):
                raise SipUnpackError('invalid header: %r' % line)
            k = l[0][:-1].lower()
            d[k] = len(l) != 1 and l[1] or ''
        return d


def parse_body(f, headers):
    """Return SIP body parsed from a file object, given HTTP header dict."""
    if 'content-length' in headers:
        n = int(headers['content-length'])
        body = f.read(n)
        if len(body) != n:
            raise SipNeedData('short body (missing %d bytes)' % (n - len(body)))
    elif 'content-type' in headers:
        body = f.read()
    else:
        body = ''
    return body


class Message:
    """SIP Protocol headers + body."""
    __metaclass__ = type
    __hdr_defaults__ = {}
    headers = None
    body = None

    def __init__(self, *args, **kwargs):
        if args:
            self.unpack(args[0])
        else:
            self.headers = {}
            self.body = ''
            for k, v in self.__hdr_defaults__.iteritems():
                setattr(self, k, v)
            for k, v in kwargs.iteritems():
                setattr(self, k, v)

    def unpack(self, buf):
        f = cStringIO.StringIO(buf)
        # Parse headers
        self.headers = parse_headers(f)
        # Parse body
        self.body = parse_body(f, self.headers)
        # Save the rest
        self.data = f.read()

    def pack_hdr(self):
        return ''.join(['%s: %s\r\n' % (canon_header(k), v) for k, v in self.headers.iteritems()])

    def __len__(self):
        return len(str(self))

    def __str__(self):
        return '%s\r\n%s' % (self.pack_hdr(), self.body)


class Request(Message):
        """SIP request."""
        __hdr_defaults__ = {
            'method': 'INVITE',
            'uri': 'sip:[email protected]',
            'version': '2.0',
            'headers': {'to': '', 'from': '', 'call-id': '', 'cseq': '', 'contact': ''}
        }
        __methods = dict.fromkeys((
            'ACK', 'BYE', 'CANCEL', 'INFO', 'INVITE', 'MESSAGE', 'NOTIFY',
            'OPTIONS', 'PRACK', 'PUBLISH', 'REFER', 'REGISTER', 'SUBSCRIBE',
            'UPDATE'
        ))
        __proto = 'SIP'

        def unpack(self, buf):
            f = cStringIO.StringIO(buf)
            line = f.readline()
            l = line.strip().split()
            if len(l) != 3 or l[0] not in self.__methods or not l[2].startswith(self.__proto):
                raise SipUnpackError('invalid request: %r' % line)
            self.method = l[0]
            self.uri = l[1]
            self.version = l[2][len(self.__proto) + 1:]
            Message.unpack(self, f.read())

        def __str__(self):
            return '%s %s %s/%s\r\n' % (self.method, self.uri, self.__proto,
                self.version) + Message.__str__(self)


class Response(Message):
    """SIP response."""

    __hdr_defaults__ = {
        'version': '2.0',
        'status': '200',
        'reason': 'OK',
        'headers': {'to': '', 'from': '', 'call-id': '', 'cseq': '', 'contact': ''}
    }
    __proto = 'SIP'

    def unpack(self, buf):
        f = cStringIO.StringIO(buf)
        line = f.readline()
        l = line.strip().split(None, 2)
        if len(l) < 2 or not l[0].startswith(self.__proto) or not l[1].isdigit():
            raise SipUnpackError('invalid response: %r' % line)
        self.version = l[0][len(self.__proto) + 1:]
        self.status = l[1]
        self.reason = l[2]
        Message.unpack(self, f.read())

    def __str__(self):
        return '%s/%s %s %s\r\n' % (self.__proto, self.version, self.status,
            self.reason) + Message.__str__(self)


def render_template(template, template_vars):
    for k in template_vars.keys():
        if k.startswith("."):
            template_vars[k[1:]] = eval(template_vars[k])
    try:
        ret = template % template_vars
    except KeyError, e:
        sys.stderr.write("ERROR: missing template variable. %s\n" % e)
        sys.exit(-1)
    except Exception, e:
        sys.stderr.write("ERROR: error in template processing. %s\n" % e)
        sys.exit(-1)
    return ret


def gen_request(template_vars, options):

        for i in xrange(options.count):
            template_vars["seq"] = i
            for k in template_vars.keys():
                if k.startswith("."):
                    template_vars[k[1:]] = eval(template_vars[k])

            if options.request_template is None:
                request = render_template(def_request, template_vars)
            else:
                try:
                    f = open(options.request_template)
                    file_request = f.read()
                    f.close()
                    request = render_template(file_request, template_vars)
                except Exception, e:
                    sys.stderr.write("ERROR: cannot open file %s. %s\n" % (options.request_template, e))
                    sys.exit(-1)
        try:
            req = Request(request)
        except SipUnpackError, e:
            sys.stderr.write("ERROR: malformed SIP Request. %s\n" % e)
            sys.exit(-1)

        if "cseq" not in req.headers:
            req.headers["cseq"] = "%d %s" % (i, req.method)
        yield str(req)


def open_sock(options):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
            sock.setblocking(0)
        except Exception, e:
            sys.stderr.write("ERROR: cannot create socket. %s\n" % e)
            sys.exit(-1)
        try:
            sock.seckopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.seckopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except AttributeError:
            pass
        if options.source_port:
            sock.bind((options.source_ip, options.source_port))
        sock.settimeout(options.wait)
        return sock


def print_reply(buf, template_vars=None, out_regex=None, out_replace=None, err=None, verbose=False, quiet=False):
    src_ip = buf[1][0]
    src_port = buf[1][1]
    template_vars['sock_src_ip'] = src_ip
    template_vars['sock_src_port'] = src_port

    try:
        resp = Response(buf[0])
    except SipUnpackError, e:
        resp = Request(buf[0])

    if resp.__class__.__name__ == "Response":
        template_vars['status'] = resp.status
        template_vars['reason'] = resp.reason
        if not out_regex:
            out_regex = '(.*\n)*'
        if not out_replace:
            out_replace = "received Response %(status)s %(reason)s from %(sock_src_ip)s:%(sock_src_port)s cseq=%(seq)s\n" % template_vars
        elif resp.__class__.__name__ == "Request":
            template_vars['method'] = resp.method
            template_vars['uri'] = resp.uri
        if not out_replace:
            out_regex = '(.*\n)*'
        if not out_replace:
            out_replace = "received Request %(method)s %(uri)s from %(sock_src_ip)s:%(sock_src_port)s cseq=%(seq)s\n" % template_vars
        if verbose:
            sys.stderr.write("%s\n" % resp)

    if True:
        try:
            out = re.sub(out_regex, out_replace, "%s" % resp)
            # replaced_out = CustomTemplate(out).safe_substitute(template_vars)
            replaced_out = out % template_vars
            print replaced_out
        except Exception, e:
            sys.stderr.write("ERROR: an issue is occoured applying regex substitution:\n")
            sys.stderr.write("\t-----------------------------------\n")
            sys.stderr.write("\t%s\n" % e)
            sys.stderr.write("\t-----------------------------------\n")
            sys.stderr.write("\tTemplate vars:\n")
            for k in template_vars:
                sys.stderr.write("\t\t%s:'%s'\n" % (k, template_vars[k]))
            sys.stderr.write("\tRegex: '%s'\n" % out_regex)
            sys.stderr.write("\tSubstitution string: '%s'\n" % out_replace)
            sys.stderr.write("\tSubstitution text: '%s'\n" % replaced_out)
            sys.stderr.write("\tResponse: \n")
            sys.stderr.write("\t-----------------------------------\n\t")
            sys.stderr.write("\n\t".join(resp.__str__().split("\n")))
            sys.stderr.write("-----------------------------------\n")
            sys.stderr.write("%s\n" % resp)
        return True


def main():
        usage = """%prog [OPTIONS]"""
        opt = optparse.OptionParser(usage=usage)
        opt.add_option('-c', dest='count', type='int', default=sys.maxint,
           help='Total number of queries to send')
        opt.add_option('-i', dest='wait', type='float', default=1,
           help='Specify packet send interval time in seconds')
        opt.add_option('-T', dest='timeout', type='float', default=1,
           help='Specify receiving timeout in seconds')
        opt.add_option('-v', dest='var', type='string', default=[""], action='append',
           help='add a template variable in format varname:value')
        opt.add_option('-V', dest='verbose', default=False, action='store_true',
           help='be verbose dumping full requests / responses')
        opt.add_option('-q', dest='quiet', default=False, action='store_true',
           help='be quiet and never print any report')
        opt.add_option('-a', dest='aggressive', default=False, action='store_true',
           help='aggressive mode: ignore any response')
        opt.add_option('-S', dest='source_ip', type='string', default="0.0.0.0",
           help='Specify ip address to bind for sending and receiving UDP datagrams')
        opt.add_option('-P', dest='source_port', type='int', default=5060,
           help='Specify the port number to use as a source port in UDP datagrams')
        opt.add_option('-d', dest='dest_ip', type='string', default=None,
           help='*mandatory* Specify the destination ip address')
        opt.add_option('-p', dest='dest_port', type='int', default=5060,
           help='*mandatory* Specify the destination port number')
        opt.add_option('-r', dest='request_template', type='string', default=None,
           help='Specify the request template file')
        opt.add_option('-t', dest='print_template', action="store_true", default=False,
            help='print the default request template')
        opt.add_option('-m', dest='modules', type='string', default=[], action='append',
           help='load additionals Python modules used in Python interpreted template variables')
        opt.add_option('-O', dest='out_regex', type='string', default="",
           help='regex to apply to response received, (default \'(.*\n)*\')')
        opt.add_option('-R', dest='out_replace', type='string', default="",
            help='print this replace string applied to the response')

        options, args = opt.parse_args(sys.argv[1:])
        if options.print_template:
            sys.stderr.write("%s\n" % def_request)
            sys.exit()

        for m in options.modules:
            globals()[m] = __import__(m)

        if not options.dest_ip:
            sys.stderr.write("ERROR: destination ip not defined\n")
            opt.print_help()
            sys.exit(-1)

        template_vars = {
            "source_ip": options.source_ip,
            "source_port": options.source_port,
            "dest_ip": options.dest_ip,
            "dest_port": options.dest_port
        }

        # first var is empty by default
        for v in options.var[1:]:
            try:
                key = v.split(":")[0]
                val = ":".join(v.split(":")[1:])
                template_vars.update({key: val})
            except IndexError:
                sys.stderr.write("ERROR: variables must be in format name:value. %s\n" % v)
                opt.print_help()
                sys.exit()

        if options.verbose:
            sys.stderr.write("=======================================\n")
            sys.stderr.write("I'm using these variables in templates: \n")
            sys.stderr.write("=======================================\n")
            for k in template_vars:
                sys.stderr.write("%s: %s\n" % (k, template_vars[k]))
            sys.stderr.write("=======================================\n\n")

        try:
            sock = open_sock(options)
        except Exception, e:
            sys.stderr.write("ERROR: cannot open socket. %s\n" % e)
            sys.exit(-1)

        sent = rcvd = 0

        try:
            for req in gen_request(template_vars, options):
                try:
                    sip_req = Request(req)
                    # Add Content-Lenght if missing
                    if "content-length" not in sip_req.headers:
                        sip_req.headers["content-length"] = len(sip_req.body)

                    try:
                        sock.sendto(str(sip_req), (options.dest_ip, options.dest_port))
                    except Exception, e:
                        sys.stderr.write("ERROR: cannot send packet to %s:%d. %s\n" % (options.dest_ip, options.dest_port, e))
                    if not options.quiet:
                        sys.stderr.write("sent Request %s to %s:%d cseq=%s len=%d\n" % (sip_req.method, options.dest_ip, options.dest_port, sip_req.headers['cseq'].split()[0], len(str(sip_req))))
                        if options.verbose:
                            sys.stderr.write("\n=== Full Request sent ===\n\n")
                            sys.stderr.write("%s\n" % sip_req)
                    sent += 1

                    if not options.aggressive:
                        read = [sock]
                        inputready, outputready, exceptready = select.select(read, [], [], options.timeout)
                        for s in inputready:
                            if s == sock:
                                buf = None
                                buf = sock.recvfrom(0xffff)
                                print_reply(buf, template_vars, options.out_regex, options.out_replace, verbose=options.verbose, quiet=options.quiet)
                                rcvd += 1

                except socket.timeout:
                    pass
                time.sleep(options.wait)
        except KeyboardInterrupt:
            pass

        if not options.quiet:
            sys.stderr.write('\n--- statistics ---\n')
            sys.stderr.write('%d packets transmitted, %d packets received, %.1f%% packet loss\n' % (sent, rcvd, (float(sent - rcvd) / sent) * 100))


if __name__ == '__main__':
        main()
The code is envoked from a command line that i assign the variable "body" a url. the url gets added to the message but there are extra line feeds. I need those gone. IE: it looks like this

Message Body
http://192.168.10.20/n
/n
/n
/n
/n

Can someone help me out in getting rid of the extra stuff?

Thanks alot
Reply
#2
Looks like a job to me.
Add required information for posting in jobs, including compensation offered, and repost or have moved to jobs
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Help moding python script to edit Gcode AntaresSky 13 4,927 Jan-04-2021, 06:29 AM
Last Post: buran
  How do I edit saved Python 3 script? Mocap 1 2,003 Jul-17-2019, 08:41 AM
Last Post: perfringo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020