diff --git a/RunTest.sh b/RunTest.sh new file mode 100644 index 0000000..a2e1cfa --- /dev/null +++ b/RunTest.sh @@ -0,0 +1,2 @@ +#!/bin/bash +ansible-playbook checkNet.yml -i hosts --extra-vars "inventory=checkNet-matrix.yml" diff --git a/checkNet-matrix.yml b/checkNet-matrix.yml new file mode 100644 index 0000000..6a93fe3 --- /dev/null +++ b/checkNet-matrix.yml @@ -0,0 +1,27 @@ +matrix: + # Shoud be NOK with netcat and iptable start on 219 + - {SRC: 192.168.124.218, DST: 192.168.124.219, Port: 2222, Proto: http, Message: 'http://127.0.0.1', Status: NO ACCESS with private service, Result1: [], Result2: []} + + - {SRC: 192.168.124.218, DST: 192.168.124.219, Port: 2222, Proto: udp, Message: 'test', Status: NO ACCESS with private service, Result1: [], Result2: []} + + # Shoud be OK with netcat and iptable start off 218 + - {SRC: 192.168.124.219, DST: 192.168.124.218, Port: 2222, Proto: tcp, Message: 'test', Status: OK, Result1: [], Result2: [u'test']} + - {SRC: 192.168.124.219, DST: 192.168.124.218, Port: 2222, Proto: udp, Message: 'test', Status: OK, Result1: [], Result2: [u'test']} + + # Should be OK + - {SRC: 192.168.124.218, DST: 192.168.124.219, Port: 22, Proto: tcp, Message: 'test', Status: OK, Result1: [u'SSH-2.0-OpenSSH_5.3', u'Protocol mismatch.'], Result2: } + - {SRC: 192.168.124.219, DST: 192.168.124.218, Port: 22, Proto: tcp, Message: 'test', Status: OK, Result1: [u'SSH-2.0-OpenSSH_5.3', u'Protocol mismatch.'], Result2: } + + # Shoud be SRC Error + #- {SRC: 192.168.124.217, DST: 192.168.124.218, Port: 2222, Proto: tcp, Message: 'test', Status: SRC ERROR, Result1: , Result2: } + ## Shoud be DST ERROR + #- {SRC: 192.168.124.219, DST: 192.168.124.217, Port: 2222, Proto: tcp, Message: 'test', Status: DST ERROR, Result1: [], Result2: } + + + - {SRC: 192.168.124.218, DST: 192.168.124.219, Port: 2222, Proto: http, BACKEND: 192.168.124.218, BACKENDPort: 1234, Message: '', Status: NO ACCESS with private service, Result1: [], Result2: []} + - {SRC: 192.168.124.219, DST: 192.168.124.218, Port: 222, Proto: http, BACKEND: 192.168.124.219, BACKENDPort: 1234, Message: '', Status: OK, Result1: [u'OK'], Result2: [u'Service Unavailable']} + - {SRC: 192.168.124.219, DST: 192.168.124.218, Port: 222, Proto: http, BACKEND: 192.168.124.218, BACKENDPort: 1234, Message: '', Status: OK, Result1: [u'Service Unavailable'], Result2: [u'OK']} + + +# MESSAGE: chaine de caractere envoyée au serveur, celui-ci renvoyant la chaine. Si les 2 chaines sont identiques, le status est OK, sinon, il est Changed +# Si leprotocol est HTTP, ce champs n'est pas utilisé. Le status est OK si le code d'erreur HTTP est 2xx ou 3xx, dans les autres cas, il est Changed diff --git a/checkNet.yml b/checkNet.yml new file mode 100644 index 0000000..31aca33 --- /dev/null +++ b/checkNet.yml @@ -0,0 +1,14 @@ +--- +- hosts: localhost + gather_facts: no + + vars_files: + - "{{inventory}}" + + tasks: + + - name: test + include: sub-test.yml Flux={{item}} + register: result + with_items: "{{matrix}}" + diff --git a/hosts b/hosts new file mode 100644 index 0000000..9769290 --- /dev/null +++ b/hosts @@ -0,0 +1,2 @@ +[WEB] +localhost ansible_connection=local diff --git a/library/sockClient.py b/library/sockClient.py new file mode 100755 index 0000000..b7bb9bd --- /dev/null +++ b/library/sockClient.py @@ -0,0 +1,101 @@ +#!/usr/bin/python + +import socket, sys +from ansible.module_utils.basic import * +import httplib +import re +import time + +BUFFER_SIZE = 1024 + +def TCP(IP, PORT, TIMEOUT, MESSAGE): + data="" + ERROR="" + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# Check if serveur is TCP UP + try: + s.settimeout(TIMEOUT) + s.connect((IP, PORT)) + s.send(MESSAGE+"\n") + while len(data) == 0: + data = s.recv(BUFFER_SIZE) + if not data: break + print data + except socket.error as msg: + if len(data) == 0: + ERROR= "Couldnt connect with the socket-server: %s\n " % msg + return True,False, data,ERROR + + s.shutdown(socket.SHUT_RDWR) + s.close() + return False,data!=MESSAGE, data,"" + +def UDP(IP, PORT, TIMEOUT, MESSAGE): + data="" + ERROR="" + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(TIMEOUT) + s.connect((IP, PORT)) + s.sendto(MESSAGE,(IP, PORT)) + while len(data) == 0: + data = s.recv(BUFFER_SIZE) + if not data: break + print data + except socket.error as msg: + if len(data) == 0: + ERROR= "Couldnt connect with the socket-server: %s\n " % msg + return True,False, data,ERROR + + s.close() + return False,data!=MESSAGE, data,ERROR + +def HTTP(IP, PORT, TIMEOUT, URL): + ERROR="" + time.sleep(TIMEOUT) + try: + conn = httplib.HTTPConnection(IP, PORT, timeout=TIMEOUT) + req=conn.request("HEAD", URL) + resp=conn.getresponse() + except Exception as msg: + ERROR=str(msg) + return True,False, "",ERROR + + #return False,re.match("^[23]\d\d$", str(resp.status))!=True, str(resp.reason)+re.match("^[23]\d\d$", "200")+".."+re.match("^[23]\d\d$", "400"),str(resp.status) + return False,not(str(resp.status).startswith("2")|str(resp.status).startswith("3")), str(resp.reason),str(resp.status) + +def main(): + fields = { + "BindIP": {"required": True, "type": "str"}, + "Port": {"required": True, "type": "int"}, + "Message": {"default": "", "type": "str"}, + "Timeout": {"default": 5, "type": "int"}, + "Protocol": { + "default": "tcp", + "choices": ['tcp', 'udp','http'], + "type": 'str', + }, + } + + module = AnsibleModule(argument_spec=fields) + + result=False + IP = module.params["BindIP"] + PORT = module.params["Port"] + PROTO=module.params["Protocol"] + MESSAGE=module.params["Message"] + TIMEOUT=module.params["Timeout"] + + + if PROTO.upper() == "TCP": + Failed, Changed, Out, Err=TCP(IP, PORT,TIMEOUT,MESSAGE) + elif PROTO.upper() == "UDP": + Failed,Changed, Out, Err=UDP(IP, PORT,TIMEOUT,MESSAGE) + elif PROTO.upper() == "HTTP": + Failed,Changed, Out, Err=HTTP(IP, PORT,TIMEOUT,MESSAGE) + + module.exit_json(changed=Changed,failed=Failed,stderr=Err, stdout=Out) + +if __name__ == '__main__': + main() + diff --git a/library/sockServer.py b/library/sockServer.py new file mode 100755 index 0000000..b5532ef --- /dev/null +++ b/library/sockServer.py @@ -0,0 +1,102 @@ +#!/usr/bin/python +import sys, socket +from ansible.module_utils.basic import * +from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer + + + + +BUFFER_SIZE = 1024 # Normally 1024, but we want fast response + +def TCP(IP, PORT) : + data="" + tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + tcp.bind((IP, PORT)) + except socket.error as msg: + print "Couldnt connect with the socket-server: %s\n terminating program" % msg + return True,"",msg + tcp.listen(1) + + conn, addr = tcp.accept() + print 'Connection address:', addr + while len(data) == 0: + Failed=False + data = conn.recv(BUFFER_SIZE) + if not data: break + print "received TCP data:", data + conn.send(data) # echo + conn.close() + return False,data, "" + +def UDP(IP,PORT): + data="" + udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + udp.bind((IP, PORT)) + except socket.error as msg: + print "Couldnt connect with the socket-server: %s\n terminating program" % msg + return True, "", msg + while len(data) == 0: + Failed=False + data, addr = udp.recvfrom(8000) + if not data: break + print "Recv UDP data:'%s'" % data + udp.sendto(data,addr) + udp.close() + return False,data,"" + + + + + + +class always200Handler(BaseHTTPRequestHandler): + def do_HEAD(self): + self.send_response(200) + self.send_header('Content-type','text/html') + self.end_headers() + # Send the html message + self.wfile.write("Jeronimo!") + return False,"","" + +def HTTP(IP,PORT): + server_address = (IP, PORT) + try: + httpd=HTTPServer(server_address,always200Handler) + httpd.serve_forever() + except Exception as msg: + httpd.socket.close() + return False, "","" + + +def main(): + fields = { + "BindIP": {"default": "0.0.0.0", "type": "str"}, + "Port": {"required": True, "type": "int"}, + "Protocol": { + "default": "tcp", + "choices": ['tcp', 'udp','http'], + "type": 'str', + }, + } + + module = AnsibleModule(argument_spec=fields) + + result=False + IP = module.params["BindIP"] + PORT = module.params["Port"] + PROTO=module.params["Protocol"] + + if PROTO.upper() == "TCP": + result, data, msg=TCP(IP, PORT) + elif PROTO.upper() == "UDP": + result,data, msg=UDP(IP, PORT) + elif PROTO.upper() == "HTTP": + result,data, msg=HTTP(IP, PORT) + + module.exit_json(changed=False,failed=result, stderr=str(msg), stdout=str(data) ) + +if __name__ == '__main__': + main() diff --git a/sub-test.yml b/sub-test.yml new file mode 100644 index 0000000..8dd5add --- /dev/null +++ b/sub-test.yml @@ -0,0 +1,85 @@ +--- +- name: "####### Starting Tests #######" + debug: msg="Running connection tests for {{Flux}}" + +- name: setting result OK + set_fact: result="OK" + +- block: + - name: SRC SSHabble + wait_for: host="{{Flux.SRC}}" port=22 state=started delay=0 timeout=1 connect_timeout=1 + register: SRC_test + + rescue: + - name: SRC not SSHable + set_fact: result="SRC ERROR" + +##### SRC is SSHable +- block: + - name: 1st test TCP + sockClient: BindIP="{{Flux.DST}}" Port="{{Flux.Port}}" Protocol="{{Flux.Proto}}" Message="{{Flux.Message}}" + register: test1 + delegate_to: "{{Flux.SRC}}" + remote_user: ansible_user + + #- name: is test on BACKEND? + #set_fact: result="PORT CLOSED" + #when: Flux.Proto|upper=="HTTP" and Flux.BACKEND is defined + + rescue: + - block: +##### SRC is SSHable and DST Port not open + - name: test remote SSH + wait_for: host="{{Flux.DST|default(Flux.DST)}}" port=22 state=started delay=0 timeout=1 connect_timeout=1 + + - name: DST Port not reachable + set_fact: result="PORT CLOSED" + + rescue: + - name: DST not SSHable + set_fact: result="DST ERROR" + + when: result == "OK" + +##### SRC is SSHable and DST Port not open and DST is SSHable +- block: + - name: setup new server + sockServer: Port="{{Flux.BACKENDPort|default(Flux.Port)}}" Protocol="{{Flux.Proto}}" + async: 10 + delegate_to: "{{Flux.BACKEND|default(Flux.DST)}}" + remote_user: ansible_user + become: true + become_user: root + + - name: 2nd test TCP local + #script: templates/sockClient.py "{{Flux.DST}}" "{{Flux.Port}}" "{{Flux.Proto}}" "toto" + sockClient: BindIP="{{Flux.DST}}" Port="{{Flux.Port}}" Protocol="{{Flux.Proto}}" Message="{{Flux.Message}}" + delegate_to: "{{Flux.SRC}}" + register: test2 + remote_user: ansible_user + + - name: setting result OK + set_fact: result="OK" + +# +##### SRC is SSHable and DST Port not open and DST is SSHable and DST Port still not openn + rescue: + - name: setting result ERROR + set_fact: result="NO ACCESS with private service" + + when: result == "PORT CLOSED" or (Flux.Proto|upper=="HTTP" and Flux.BACKEND is defined) + +- name: save result + lineinfile: + dest="{{inventory}}" + regexp="(?! .#)(?!.*BACKEND.*)( {{Flux.SRC}},.* {{Flux.DST}},.* {{Flux.Port}},.* {{Flux.Proto}},.*{{Flux.Message}}.*)$" + line=" - {SRC{{":"}} {{Flux.SRC}}, DST{{":"}} {{Flux.DST}}, Port{{":"}} {{Flux.Port}}, Proto{{":"}} {{Flux.Proto}}, Message{{":"}} '{{Flux.Message}}', Status{{":"}} {{result}}, Result1{{":"}} {{test1.stdout_lines|default("")}}, Result2{{":"}} {{test2.stdout_lines|default("")}}}" + when: "Flux.BACKEND is not defined" + +- name: save BACKEND result + lineinfile: + dest="{{inventory}}" + regexp="((?! *#.*).).* {{Flux.SRC}},.* {{Flux.DST}},.* {{Flux.Port}},.* {{Flux.Proto}},.* {{Flux.BACKEND}},.* {{Flux.BACKENDPort}},.*{{Flux.Message}}.*" + line=" - {SRC{{":"}} {{Flux.SRC}}, DST{{":"}} {{Flux.DST}}, Port{{":"}} {{Flux.Port}}, Proto{{":"}} {{Flux.Proto}}, BACKEND{{":"}} {{Flux.BACKEND}}, BACKENDPort{{":"}} {{ Flux.BACKENDPort}}, Message{{":"}} '{{Flux.Message}}', Status{{":"}} {{result}}, Result1{{":"}} {{test1.stdout_lines|default("")}}, Result2{{":"}} {{test2.stdout_lines|default("")}}}" + when: "Flux.BACKEND is defined" +