pysap.SAPRouter module

exception pysap.SAPRouter.SAPRouteException[source]

Bases: Exception

Exception for SAP Router routing errors

class pysap.SAPRouter.SAPRoutedStreamSocket(sock, route, talk_mode=None, router_version=None, keep_alive=True, base_cls=None)[source]

Bases: SAPNIStreamSocket

Stream socket implementation for a connection routed through a SAP Router server. It works by wrapping a SAPNIStreamSocket and connecting first to the SAP Router given a route string or list of SAPRouterRouteHop.

desc = 'NI Stream socket routed trough a SAP Router'
classmethod get_nisocket(host=None, port=None, route=None, password=None, talk_mode=None, router_version=None, **kwargs)[source]

Helper function to obtain a SAPRoutedStreamSocket. If no route is specified, it returns a plain SAPNIStreamSocket. If no route is specified and the talk mode is raw, it returns a plain StreamSocket as it’s assumed that the NI layer is not desired.

Parameters:
  • host (C{string}) – target host to connect to if not specified in the route

  • port (int) – target port to connect to if not specified in the route

  • route (C{string} or list of SAPRouterRouteHop) – route to use for determining the SAP Router to connect

  • password (C{string}) – target password if not specified in the route

  • talk_mode (int) – the talk mode to use for requesting the route

  • router_version (int) – the router version to use for requesting the route

  • kwargs – arguments to pass to SAPRoutedStreamSocket constructor

Returns:

connected socket through the specified route

Return type:

SAPRoutedStreamSocket

Raises:
  • SAPRouteException – if the route request to the target host/port was not accepted by the SAP Router

  • socket.error – if the connection to the target host/port failed or the SAP Router returned an error

recv()[source]

Receive a packet from the target host. If the talk mode in use is native and we’ve already set the route, the packet received is a raw packet. Otherwise, the packet received is a NI layer packet in the same way the SAPNIStreamSocket works.

route_to(route, talk_mode)[source]

Make the route request to the target host/service.

Parameters:
  • route (list of SAPRouterRouteHop) – a route to specify to the SAP Router

  • talk_mode (int) – the talk mode to use when routing

Raises:
  • SAPRouteException – if the route request to the target host/port was not accepted by the SAP Router

  • socket.error – if the connection to the target host/port failed or the SAP Router returned an error

send(packet)[source]

Send a packet. If the talk mode in use is native the packet sent is a raw packet. Otherwise, the packet is a NI layer packet in the same way the SAPNIStreamSocket works.

Parameters:

packet (Packet) – packet to send

class pysap.SAPRouter.SAPRouter(_pkt, /, *, type=b'NI_ROUTE', version=2, route_ni_version=40, route_entries=0, route_talk_mode=0, route_padd=0, route_rest_nodes=0, route_length=0, route_offset=0, route_string=[], adm_command=2, adm_unused=0, adm_password=b'', adm_client_count=None, adm_client_count_trace=None, adm_client_ids=[0], adm_address_mask=b'', opcode=0, opcode_padd=0, return_code=0, err_text_length=None, err_text_value=<SAPRouterError  |>, err_text_unknown=0, control_text_length=0, control_text_value=b'*ERR', snc_frame=None)[source]

Bases: Packet

SAP Router packet

This packet is used for general SAP Router packets. There are (at least) five types of SAP Router packets:

1. Route packets. For requesting the routing of a connection to a remote hosts. The packet contains some general information and a connection string with a list of routing hops (SAPRouterRouteHop).

2. Administration packets. This packet is used for the SAP Router to send administrative commands. It’s suppose to be used only from the hosts running the SAP Router or when an specific route is included in the routing table. Generally administration packets are not accepted from the external binding.

  1. Error Information packets. Packets sent when an error occurred.

4. Control Message packets. Used to perform some control activities, like retrieving the current SAPRouter version or to perform the SNC handshake. They have the same structure that error information packets.

5. Route accepted packet. Used to acknowledge a route request (“NI_PONG”).

Routed packets and some responses doesn’t fill in these five packet types. For identifying those cases, you should check the type using the function router_is_known_type.

NI Versions found (unconfirmed):
  • 30: Release 40C

  • 36: Release <6.20

  • 38: Release 7.00/7.10

  • 39: Release 7.11

  • 40: Release 7.20/7.21

SAPROUTER_ADMIN = b'ROUTER_ADM'
Cvar:

Constant for administration packets

Type:

C{bytes}

SAPROUTER_CONTROL = b'NI_RTERR'
Cvar:

Constant for control messages packets

Type:

C{bytes}

SAPROUTER_DEFAULT_VERSION = 40
SAPROUTER_ERROR = b'NI_RTERR'
Cvar:

Constant for error information packets

Type:

C{bytes}

SAPROUTER_PONG = b'NI_PONG'
Cvar:

Constant for route accepted packets

Type:

C{bytes}

SAPROUTER_ROUTE = b'NI_ROUTE'
Cvar:

Constant for route packets

Type:

C{bytes}

aliastypes = [<class 'pysap.SAPRouter.SAPRouter'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<StrNullField (SAPRouter).type>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>, <scapy.fields.ConditionalField object>]
router_type_values = [b'ROUTER_ADM', b'NI_RTERR', b'NI_RTERR', b'NI_ROUTE', b'NI_PONG']
Cvar:

List of known packet types

Type:

list of C{string}

class pysap.SAPRouter.SAPRouterError(_pkt, /, *, eyecatcher=b'*ERR*', counter=b'1', error=b'', return_code=b'', component=b'NI (network interface)', release=b'', version=b'', module=b'nirout.cpp', line=b'', detail=b'', error_time=b'', system_call=b'', errorno=b'', errorno_text=b'', error_count=b'', location=b'', XXX5=b'', XXX6=b'', XXX7=b'', XXX8=b'', eyecatcher_end=b'*ERR*')[source]

Bases: PacketNoPadded

SAP Router Protocol Error Text

This packet is used to describe an error returned by SAP Router.

aliastypes = [<class 'pysap.SAPRouter.SAPRouterError'>, <class 'pysap.utils.fields.PacketNoPadded'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<StrNullField (SAPRouterError).eyecatcher>, <StrNullField (SAPRouterError).counter>, <StrNullField (SAPRouterError).error>, <StrNullField (SAPRouterError).return_code>, <StrNullField (SAPRouterError).component>, <StrNullField (SAPRouterError).release>, <StrNullField (SAPRouterError).version>, <StrNullField (SAPRouterError).module>, <StrNullField (SAPRouterError).line>, <StrNullField (SAPRouterError).detail>, <StrNullField (SAPRouterError).error_time>, <StrNullField (SAPRouterError).system_call>, <StrNullField (SAPRouterError).errorno>, <StrNullField (SAPRouterError).errorno_text>, <StrNullField (SAPRouterError).error_count>, <StrNullField (SAPRouterError).location>, <StrNullField (SAPRouterError).XXX5>, <StrNullField (SAPRouterError).XXX6>, <StrNullField (SAPRouterError).XXX7>, <StrNullField (SAPRouterError).XXX8>, <StrNullField (SAPRouterError).eyecatcher_end>]
time_format = '%a %b %d %H:%M:%S %Y'
Cvar:

Format to use when building the time field

Type:

C{string}

class pysap.SAPRouter.SAPRouterInfoClient(_pkt, /, *, id=1, flag_XXX1=0, flag_XXX2=0, flag_XXX3=0, flag_XXX4=0, flag_XXX5=0, flag_traced=0, flag_connected=0, flag_routed=0, connected_on=0, address=None, partner=None, service=None, XXX3=None)[source]

Bases: PacketNoPadded

SAP Router Protocol Information Request Client info

This packet is used to return the information of a connected client.

aliastypes = [<class 'pysap.SAPRouter.SAPRouterInfoClient'>, <class 'pysap.utils.fields.PacketNoPadded'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<IntField (SAPRouterInfoClient).id>, <BitField (SAPRouterInfoClient).flag_XXX1>, <BitField (SAPRouterInfoClient).flag_XXX2>, <BitField (SAPRouterInfoClient).flag_XXX3>, <BitField (SAPRouterInfoClient).flag_XXX4>, <BitField (SAPRouterInfoClient).flag_XXX5>, <BitField (SAPRouterInfoClient).flag_traced>, <BitField (SAPRouterInfoClient).flag_connected>, <BitField (SAPRouterInfoClient).flag_routed>, <LongField (SAPRouterInfoClient).connected_on>, <StrNullFixedLenField (SAPRouterInfoClient).address>, <StrNullFixedLenField (SAPRouterInfoClient).partner>, <StrNullFixedLenField (SAPRouterInfoClient).service>, <StrFixedLenField (SAPRouterInfoClient).XXX3>]
class pysap.SAPRouter.SAPRouterInfoClients(_pkt, /, *, clients=[])[source]

Bases: PacketNoPadded

SAP Router Protocol Information Request Client info list

This packet is used to return the list of current connected clients.

aliastypes = [<class 'pysap.SAPRouter.SAPRouterInfoClients'>, <class 'pysap.utils.fields.PacketNoPadded'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<PacketListField (SAPRouterInfoClients).clients>]
class pysap.SAPRouter.SAPRouterInfoServer(_pkt, /, *, pid=0, ppid=0, started_on=0, port=0, pport=0)[source]

Bases: PacketNoPadded

SAP Router Protocol Information Request Server info

This packet is used to return information about the SAP Router

aliastypes = [<class 'pysap.SAPRouter.SAPRouterInfoServer'>, <class 'pysap.utils.fields.PacketNoPadded'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<IntField (SAPRouterInfoServer).pid>, <IntField (SAPRouterInfoServer).ppid>, <LongField (SAPRouterInfoServer).started_on>, <ShortField (SAPRouterInfoServer).port>, <ShortField (SAPRouterInfoServer).pport>]
class pysap.SAPRouter.SAPRouterNativeProxy(bind_address, bind_port, remote_address, remote_port, handler, target_address, target_port, target_pass=None, talk_mode=0, backlog=5, keep_alive=True, options=None)[source]

Bases: SAPNIProxy

SAP Router Native Proxy

Proxy implementation that routes traffic through a remote SAP Router server to a target host/port. It works by binding a SAPNIStreamSocket and requesting the SAP Router a route to the target location. If the route is accepted it keeps the listener open for connections and spawn a new SAPRouterNativeRouterHandler instance for each client.

Example usage:

proxy = SAPRouterNativeProxy(local_host, local_port,
                             remote_host, remote_port,
                             SAPRouterNativeRouterHandler,
                             target_address=target_address,
                             target_post=target_port,
                             target_pass=target_pass)
proxy.handle_connection()
handle_connection()[source]

Block until a connection is received from the listener, request a route to forward the traffic through the remote SAP Router and handle the client using the provided handler class.

Returns:

the handler instance handling the request

Return type:

SAPNIProxyHandler

route()[source]

Requests a route to forward the traffic through the remote SAP Router.

Raises:
  • SAPRouteException – if the route request is denied

  • Exception – if an error occurred when requesting the route

class pysap.SAPRouter.SAPRouterNativeRouterHandler(client, server, options=None)[source]

Bases: SAPNIProxyHandler

SAP Router Native Proxy Handler

Handles packets routed through a remote SAP Router. It works by bypassing the SAP NI layer in order to allow native traffic.

recv_send(local, remote, process)[source]

Receives data from one socket connection, process it and send to the remote connection.

Parameters:
  • local (SAPNIStreamSocket) – the local socket

  • remote (SAPNIStreamSocket) – the remote socket

  • process (function) – the function that process the incoming data

class pysap.SAPRouter.SAPRouterRouteHop(_pkt, /, *, hostname=None, port=None, password=None)[source]

Bases: PacketNoPadded

SAP Router Protocol Route Hop

This packet is used to describe a hop in a route using the SAP Router.

aliastypes = [<class 'pysap.SAPRouter.SAPRouterRouteHop'>, <class 'pysap.utils.fields.PacketNoPadded'>, <class 'scapy.packet.Packet'>]
fields_desc: List[AnyField] = [<StrNullField (SAPRouterRouteHop).hostname>, <StrNullField (SAPRouterRouteHop).port>, <StrNullField (SAPRouterRouteHop).password>]
classmethod from_hops(route_hops)[source]

Build a route string from a list of route hops.

Parameters:

route_hops (list of SAPRouterRouteHop) – route hops

Returns:

route string

Return type:

C{string}

classmethod from_string(route_string)[source]

Build a list of route hops from a route string. The format of a route string is:

(/H/host/S/service/W/pass)*

or for older versions (<4.0):

(/H/host/S/service/P/pass)*

Parameters:

route_string (C{string}) – route string

Returns:

route hops in the route string

Return type:

list of SAPRouterRouteHop

regex = re.compile('\n        (/[hH]/(?P<hostname>[\\w\\.\\-]+)           # Hostname, FQDN or IP addresss\n        (/[sS]/(?P<port>[\\w]+))?                 # Optional port/service\n        (/[pwPW]/(?P<password>[\\w.]+, re.VERBOSE)
Cvar:

Regular expression for matching route strings

Type:

regex

pysap.SAPRouter.get_router_version(connection)[source]

Helper function to retrieve the version of a remote SAP Router. It uses a control packet with the ‘version request’ operation code. The version is obtained either from a valid ‘version response’ packet or from the error message packet if something happened.

Parameters:

connection (SAPNIStreamSocket) – connection with the SAP Router

Returns:

version

pysap.SAPRouter.router_adm_commands = {2: 'Information Request', 3: 'New Route Table Request', 4: 'Toggle Trace Request', 5: 'Stop Request', 6: 'Cancel Route Request', 7: 'Dump Buffers Request', 8: 'Flush Buffers Request', 9: 'Soft Shutdown Request', 10: 'Set Trace Peer', 11: 'Clear Trace Peer', 12: 'Trace Connection', 13: 'Trace Connection', 14: 'Hide Error Information Request'}

Router Administration Command values

pysap.SAPRouter.router_control_opcodes = {0: 'Error information', 1: 'Version request', 2: 'Version response', 5: 'Send Handle (5)', 6: 'Send Handle (6)', 8: 'Send Handle (8)', 70: 'SNC request', 71: 'SNC handshake complete'}

Router Opcode values

pysap.SAPRouter.router_is_admin(pkt)[source]

Returns if the packet is a Admin packet.

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is Admin

Return type:

bool

pysap.SAPRouter.router_is_control(pkt)[source]

Returns if the packet is a Control packet.

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is Control

Return type:

bool

pysap.SAPRouter.router_is_error(pkt)[source]

Returns if the packet is a Error Information packet.

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is Error

Return type:

bool

pysap.SAPRouter.router_is_known_type(pkt)[source]

Returns if the packet is of a known type (Admin, Route, Error or Pong).

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is known

Return type:

bool

pysap.SAPRouter.router_is_pong(pkt)[source]

Returns if the packet is a Pong (route accepted) packet.

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is Pong

Return type:

bool

pysap.SAPRouter.router_is_route(pkt)[source]

Returns if the packet is a Route packet.

Parameters:

pkt (SAPRouter) – packet to look at

Returns:

if the type of the packet is Route

Return type:

bool

pysap.SAPRouter.router_ni_talk_mode_values = {0: 'NI_MSG_IO', 1: 'NI_RAW_IO', 2: 'NI_ROUT_IO'}

Router NI Talk mode values

pysap.SAPRouter.router_return_codes = {-104: 'Error in the SNC shift (NIEROUT_SNC_FAILURE)', -103: 'Error in external library (NIEROUT_EXTERN)', -102: 'Client not available (NIEROUT_NOCLIENT)', -101: 'Talkmode not allowed (NIEROUT_MODE_DENIED)', -100: 'Max. number of clients reached (NIEROUT_OVERFLOW)', -99: 'Information request refused (NIEROUT_INFO_DENIED)', -98: 'saprouter shutdown (NIEROUT_SHUTDOWN)', -97: 'Connection cancelled by administrator (NIEROUT_CANCELED)', -96: 'Invalid client version (NIEROUT_VERSION)', -95: 'Connection terminated (NIEROUT_CONN_BROKEN)', -94: 'Connect from source to destination not allowed (NIEROUT_PERM_DENIED)', -93: 'NI-internal errors (NIEROUT_INTERN)', -92: 'Connection setup failed (NIEROUT_CONN_REFUSED)', -91: 'Service unknown (NIEROUT_SERV_UNKNOWN)', -90: 'Host name unknown (NIEROUT_HOST_UNKNOWN)', -20: 'Requested package too large (NIETOO_BIG)', -19: 'queue limit reached, next package not accepted (NIEQUE_FULL)', -18: 'Opcode received (NIEOPCODE)', -17: 'Error in the SNC shift in the saprouter ==> (NIESNC_FAILURE)', -16: 'Local hostname invalid (NIEMYHOST_VERIFY)', -15: 'No free port in range (NIENOFREEPORT)', -14: 'Local hostname cannot be found (NIEMYHOSTNAME)', -13: 'Invalid version (NIEVERSION)', -12: 'Connection to partner via NiRouter not yet set up (NIECONN_PENDING)', -11: 'PING/PONG signal received (NIEPING)', -10: 'Connection setup failed (NIECONN_REFUSED)', -9: 'Wake-Up (without data) (NIEWAKEUP)', -8: 'Invalid parameters (NIEINVAL)', -7: 'Data range too small (NIETOO_SMALL)', -6: 'Connection to partner broken (NIECONN_BROKEN)', -5: 'Time limit reached (NIETIMEOUT)', -4: 'Service already used (NIESERV_USED)', -3: 'Service unknown (NIESERV_UNKNOWN)', -2: 'Host name unknown (NIEHOST_UNKNOWN)', -1: 'NI-internal error (NIEINTERN)'}

Router Return Code values