This is me, Wu!
» e-shell.org
In this page
Rate this page!
Search inside the wiki!
  Home >> sources >> OpenBSD sockstat

OpenBSD sockstat

This is a little script that emulates (almost) the sockstat util from FreeBSD. Its main purpose is to let system administrators check open sockets on the system,in a quick way. Right now (v0.1) it is only a "frontend" to fstat. It calls fstat and process the output based on some parameters passed by the user on runtime. Nevertheless, it is designed in a modular basis, and you can take a look over the source code to see that you can replace CallFstat?() with another function that check the sockets directly, or another function that uses netstat instead of fstat to gather information from the system.

Download: sockstat.py v0.1 (October 24, 2005) | tar.gz | tar.bz2 | zip |

Source:

#!/usr/bin/env python
# coding: iso-8859-15
#  -*- Python -*-

""" This is a simple script which can be used as FreeBSD sockstat:

http://www.freebsd.org/cgi/man.cgi?query=sockstat&apropos=0&sektion=0&manpath=FreeBSD+5.4-stable&format=html

Right now it is only a "frontend" to fstat, from where it gather information."""

import sys, os

def ShowHelp(args):

    """ Just show how to use the script and exit. This help is based on the man
    page from FreeBSD sockstat."""

    HelpString = """
sockstat: Simple Python script to check open sockets

    Use:

        $ %s [-l[4|6]] [-c[4|6]] [-u] [port ports]

        -l[4|6]        Show listening sockets. 4 means only IPv4 sockets,
                   6 means only IPv6 sockets

        -c[4|6]        Show connected sockets. 4 means only IPv4 sockets,
                   6 means only IPv6 sockets

        -u     Show AF_LOCAL (UNIX) sockets.

        port ports Only show Internet sockets if either the local or foreign
                   port number is on the specified list. The ports argument is
                   a comma-separated list of port numbers and ranges specified
                   as first and last port separated by a dash.

                   This option will apply only if the -l argument is used too
                   (listing listening sockets).

        proto protocol
                   Show only Internet sockets of the protocol set by the
                   protocol argument. The protocol could be tcp or udp,
                   and will be used with ipv4 and ipv6 sockets.

        user username
                   Show only sockets opened by the user defined by username.

    """ % (args[0])

    print HelpString

def CallFstat():

    """ Wrapper to call fstat(1) and get the info about the sockets.
    This code is here, on a separate function in order to build a
    modular script, we could write another function in the future
    to get the information from the sockets (like using the socket module)
    and call it instead of CallFstat() from GetSocketInfo()

    This function returns 5 lists containing information about listening
    ipv4 and ipv6 sockets, connections and unix sockets."""

    pipe = os.popen('fstat')
    ipv4_listen = []
    ipv6_listen = []
    ipv4_conn = []
    ipv6_conn = []
    unix_socket = []
    pipe=os.popen('fstat')
    readed = '1'
    header = pipe.readline()
    while readed != '':
        readed = pipe.readline()
        if '* internet ' in readed:
            if '*:' in readed:
                ipv4_listen.append(readed)
            elif ':' in readed and readed.count(':') < 2:
                ipv4_listen.append(readed)
            else:
                ipv4_conn.append(readed)

        elif '* internet6 ' in readed:
            if '*:' in readed:
                ipv6_listen.append(readed)
            elif ':' in readed and readed.count(':') < 2:
                ipv6_listen.append(readed)
            else:
                ipv6_conn.append(readed)

        elif '* unix ' in readed:
            unix_socket.append(readed)

    return header, ipv4_listen, ipv6_listen, ipv4_conn, ipv6_conn, unix_socket



def GetSocketInfo(opc):

    """ This function retrieves socket information from the system and parses it to
    return the result to the main process pre-formatted.

    opc is an argument that set the kind of socket information we are asking for.

    First we call whichever function that returns the information about the sockets,
    Right now there is only one posibility: CallFstat(), which uses fstat() to get
    the information from the system."""

    header, ipv4_listen, ipv6_listen, ipv4_conn, ipv6_conn, unix_socket = CallFstat()

    SocketInfo = header

    if opc == '-l':
        for i in ipv4_listen:
            SocketInfo = SocketInfo + i
        for i in ipv6_listen:
            SocketInfo = SocketInfo + i

    elif opc == '-l4':
        for i in ipv4_listen:
            SocketInfo = SocketInfo + i

    elif opc == '-l6':
        for i in ipv6_listen:
            SocketInfo = SocketInfo + i

    elif opc == '-c':
        for i in ipv4_conn:
            SocketInfo = SocketInfo + i
        for i in ipv6_conn:
            SocketInfo = SocketInfo + i

    elif opc == '-c4':
        for i in ipv4_conn:
            SocketInfo = SocketInfo + i

    elif opc == '-c6':
        for i in ipv6_conn:
            SocketInfo = SocketInfo + i

    elif opc == '-u':
        for i in unix_socket:
            SocketInfo = SocketInfo + i

    return SocketInfo


def ApplySocketInfoFilters(SocketInfo, Arg, Params):

    """ This is a function similar to GetSocketInfo, it receives the SocketInfo string
    and parses it depending on the Arg and Params values, which could hold values
    for port number or protocol filtering."""

    if Arg == 'port':

        # port number filtering, from the string gathered from fstat, we will show only
        # ports set with port ports.
        #
        # There are some different posibilities, one port number, multiple port numbers
        # separated by commas, or a port number range, being that one 2 port numbers
        # separated with a '-' char.

        PosiblePorts = Params.split(',')
        Ports = []
        for i in PosiblePorts:
            if '-' in i and i.count('-') < 2:
                for j in range(int(i.split('-')[0]), int(i.split('-')[1]) + 1):
                    Ports.append(str(j))

            else:
                try:
                    # check if it is an integer, and add it (as a str) to the list of
                    # ports
                    int(i)
                    Ports.append(i)
                except:
                    # no integer, no problem
                    pass

        # Now we split the SocketInfo string from the '\n' character and rebuilds it with
        # the port filter applied.

        SocketInfoList = SocketInfo.split('\n')

        # We add the header again, to the new string
        ModSocketInfo = SocketInfoList[0] + '\n'

        for i in SocketInfoList:
            for j in Ports:
                if ':' in i:
                    try:
                        if int(j) == int(i.split(':')[1]):
                            ModSocketInfo = ModSocketInfo + i + '\n'
                    except:
                        # any of the checking elements is not an integer,
                        # do not crush, simply doesn't add it
                        pass

    elif Arg == 'proto':

        # protocol filtering, from the string gathered from fstat, we will show only
        # sockets of the given protocol.
        #
        # The only posibilities are tcp and udp for the ipv4 and ipv6 sockets

        ValidProtos = ['tcp', 'udp']

        if Params in ValidProtos:
            # Now we split the SocketInfo string from the '\n' character and rebuilds it with
            # the port filter applied.

            SocketInfoList = SocketInfo.split('\n')

            # We add the header again, to the new string
            ModSocketInfo = SocketInfoList[0] + '\n'

            for i in SocketInfoList:
                if Params in i.split(' '):
                    ModSocketInfo = ModSocketInfo + i + '\n'

    elif Arg == 'user':

        # user filtering, from the string gathered from fstat, we will show only
        # sockets owned by this user.

        SocketInfoList = SocketInfo.split('\n')

        # We add the header again, to the new string
        ModSocketInfo = SocketInfoList[0] + '\n'

        for i in SocketInfoList:
            if Params in i.split(' '):
                ModSocketInfo = ModSocketInfo + i + '\n'

    return ModSocketInfo


if __name__ == '__main__':

    if len(sys.argv) < 2:

        # No args, we have to show the use help
        ShowHelp(sys.argv)

    else:

        # Time to work, we will get all the args, and foreach one we call the proper
        # function to get the information about the sockets, this info is appended
        # to the string we will show at last.
        #
        # But first we remove the script name from the parameter list.

        SocketInfo = ''

        ValidArgs = ['-l','-l4','-l6','-c','-c4', '-c6',
                     '-u', 'port', 'proto', 'user']

        # this is a list of arguments that are followed by option parameter,
        # like port ports or -f filter
        ParameterArgs = ['port', 'proto', 'user']

        ProvArgs = []
        for i in sys.argv:
            ProvArgs.append(i)

        ProvArgs.remove(ProvArgs[0])

        ProvParamArgs = {}

        for i in ProvArgs:

            if i in ValidArgs:
                if i in ParameterArgs:
                    # we will apply the filter later, upon the basic string was built
                    ProvParamArgs[i] = ProvArgs[ProvArgs.index(i)+1]
                else:
                    SocketInfo = SocketInfo + GetSocketInfo(i)
            else:
                if ProvArgs[ProvArgs.index(i)-1] not in ParameterArgs:
                    print '%s: Invalid option -- %s' % (sys.argv[0], i)
                    ShowHelp(sys.argv)
                    raise SystemExit

        # Now we have the initial Information to display, now it is time to
        # apply filters, like ports and protocols
        if len(ProvParamArgs) > 0:
            for i in ProvParamArgs:
                SocketInfo = ApplySocketInfoFilters(SocketInfo, i, ProvParamArgs[i])

        # print the result and exit
        print SocketInfo