""" Server class that simualtes a server behaving as defined in the AUTOSAT standard. Each server instance is executed as a single process. """
import multiprocessing
import random
import time
from src import Configuration
from src import SomeIPPacket
from src import Msg
[docs]class Server(object):
"""
Initialization of the server object.
:param config: Own server configuration.
:param q: Own queue for receiving messages from clients.
:param writer: Queue for writing out a packet.
:param clientQueues: Queues of all available clients.
:param attackers: Attacker Queue as the attacker is implemented as MitM.
:param stopQueues: A DONE is sent to this queue if on q a DONE is received.
:param verbose: If set to True, more output is printed, default=False
"""
def __init__(self, config, q, writer, clientQueues, attackers, stopQueue, verbose=False):
# own Configuration of the server
self.config = config
# each Server has a queue for incomming messages, e.g. from Clients
self.ownQueue = q
# Queue to push the outgoing messages to
self.writerQueue = writer
# all clientQueues to push the response messages to them
self.clientQueues = clientQueues
self.attackers = attackers
# for getting Information about process, this value as to be set to True
self.verbose = verbose
self.stopQueue = stopQueue
[docs] def setName(self, name):
""" Setter for the own server name. """
self.name = name
[docs]def msgTypeSupported(msgType):
""" Checks whether or not the requested message type is supported. """
for elem in SomeIPPacket.messageTypes:
if SomeIPPacket.messageTypes[elem] == msgType:
return True
return False
def returnRequestedMethod(service, methodID):
for elem in service['methods']:
if elem['id'] == methodID:
return elem
return None
[docs]def checkServiceAndMethodKnown(service, serviceID, methodID):
""" Checks whether or not the requested service and method are provided by this instance. """
if serviceID not in service:
return False
else:
if returnRequestedMethod(service[serviceID], methodID) == None:
return False
return True
[docs]def requestedMethodIsRequest(service, serviceID, methodID):
""" Checks whether or not the requested service and method is of type REQUEST. """
if checkServiceAndMethodKnown(service, serviceID, methodID):
curMethod = returnRequestedMethod(service[serviceID], methodID)
if curMethod['type'] == SomeIPPacket.messageTypes['REQUEST']:
return True
return False
def getProbValue(errorRate):
val = random.random()
if val < errorRate:
return 1
else:
return 0
[docs]def generateRandomReply(errorRate, verbose, name):
""" Generates a random reply, with a certain defined probability, otherwise an error is sent back. """
reply = {}
value = getProbValue(errorRate)
if verbose:
print(name, ' - Given Error Rate: ', errorRate, ' choosen value', value)
# create Error
if value == 1:
if verbose:
print(name, ' - Send Error.')
reply['type'] = SomeIPPacket.messageTypes['ERROR']
errorValue = random.randint(0,5)
if errorValue == 1:
reply['ret'] = SomeIPPacket.errorCodes['E_NOT_OK']
elif errorValue == 2:
reply['ret'] = SomeIPPacket.errorCodes['E_NOT_READY']
elif errorValue == 3:
reply['ret'] = SomeIPPacket.errorCodes['E_NOT_REACHABLE']
elif errorValue == 4:
reply['ret'] = SomeIPPacket.errorCodes['E_TIMEOUT']
else:
reply['ret'] = SomeIPPacket.errorCodes['E_MALFORMED_MESSAGE']
# create normal Response
else:
if verbose:
print(name, ' - Send normal Reply.')
reply['type'] = SomeIPPacket.messageTypes['RESPONSE']
reply['ret'] = SomeIPPacket.errorCodes['E_OK']
return reply
[docs]def sendReply (msgType, msgRet, client, reply, timestamp, s):
"""
Putting everything together and send the reply/error.
:param msgType: The used message type for the reply.
:param msgRet: The used return/error code for the reply.
:param client: The client the message is sent to.
:param reply: The content of the reply.
:param timestamp: The timestamp that shall be used.
:param s: Own server instance.
"""
reply['type'] = msgType
reply['ret'] = msgRet
returnMsg = Msg.Msg(s.name, client, reply, timestamp)
s.attackers.put(returnMsg)
def setTimeStamp(timestampOriginal, minVal, maxVal, s):
timestamp = timestampOriginal + random.uniform(minVal,maxVal)
if s.verbose:
print (s.name, ' - Got Original Timestamp: ', timestampOriginal, ' using following settings: (',minVal,',',maxVal,') and Created: ', timestamp)
return timestamp
[docs]def server(s):
"""Main service function that initializes the server object, waits for incomming clients requests and responds to them."""
name = multiprocessing.current_process().name
s.setName(name)
services = s.config
print (s.name, ' Starting')
if s.verbose:
print (s.name, 'Starting with services:', services)
while (True):
msg = s.ownQueue.get()
if msg == 'Done':
s.stopQueue.put('Done')
break;
client = msg.sender
message = msg.message
timestamp = setTimeStamp(msg.timestamp, s.config[message['service']]['min'], s.config[message['service']]['max'], s)
reply = {}
reply['service'] = message['service']
reply['method'] = message['method']
reply['client'] = message['client']
reply['session'] = message['session']
reply['proto'] = SomeIPPacket.VERSION
reply['iface'] = SomeIPPacket.INTERFACE
# check if some action is needed --> the method "requested" is of type REQUEST or a plain REQUEST is sent, but service or method is unknown
if (not checkServiceAndMethodKnown(services, message['service'], message['method']) and message['type'] == SomeIPPacket.messageTypes['REQUEST']) or (requestedMethodIsRequest(services, message['service'], message['method'])):
pass
else:
if s.verbose:
print (s.name, 'IGNORE MESSAGE')
continue
# check for protocol version Number
if message['proto'] != SomeIPPacket.VERSION:
if s.verbose:
print (s.name, 'Wrong Protocol Version.')
sendReply(SomeIPPacket.messageTypes['ERROR'], SomeIPPacket.errorCodes['E_WRONG_PROTOCOL_VERSION'], name, client, reply, timestamp, writer, clientQueues[client])
continue
# check for interface version Number
if message['iface'] != SomeIPPacket.INTERFACE:
if s.verbose:
print (s.name, 'Wrong Interface Version.')
sendReply(SomeIPPacket.messageTypes['ERROR'], SomeIPPacket.errorCodes['E_WRONG_INTERFACE_VERSION'], client, reply, timestamp, s)
continue
# check if requested service is configured on server
if message['service'] not in services:
if s.verbose:
print (s.name, 'Unsupported service.')
sendReply(SomeIPPacket.messageTypes['ERROR'], SomeIPPacket.errorCodes['E_UNKNOWN_SERVICE'], client, reply, timestamp, s)
continue
curService = services[message['service']]
# check if requested method is supported
if returnRequestedMethod(curService, message['method']) == None:
if s.verbose:
print (s.name, 'Unsupported Method.')
sendReply(SomeIPPacket.messageTypes['ERROR'], SomeIPPacket.errorCodes['E_UNKNOWN_METHOD'], client, reply, timestamp, s)
continue
curMethod = returnRequestedMethod(curService, message['method'])
# check if message Type is supported
if (not msgTypeSupported(message['type'])):
if s.verbose:
print (s.name, 'IGNORE Unkown message Type.')
continue
# check for message Type, send Error if REQUEST is expected but not set
if (message['type'] != SomeIPPacket.messageTypes['REQUEST'] and msgTypeSupported(message['type'])):
if s.verbose:
print (s.name, 'Wrong Message Type.')
sendReply(SomeIPPacket.messageTypes['ERROR'], SomeIPPacket.errorCodes['E_WRONG_MESSAGE_TYPE'], client, reply, timestamp, s)
continue
generatedReply = generateRandomReply(s.config[reply['service']]['errorRate'], s.verbose, s.name)
sendReply(generatedReply['type'], generatedReply['ret'], client, reply, timestamp, s)
if s.verbose:
print (s.name, 'REPLY NEEDED')
print (s.name, 'Exiting')