def handshake(self): if self.client_state == States.CLOSED: # Step1: Generate a random sequence number. Send syn message to the server # to initiate a connection. seq_num = utils.rand_int() syn_header = utils.Header( seq_num, 0, syn=1, ) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) self.update_state(States.SYN_SENT) self.last_seq = seq_num self.handshake() elif self.client_state == States.SYN_SENT: # Step2: Rceive ack from server with syn = 1, ack = 1. header, body, addr = recv_msg() if header is None: print("Handshake failed.") self.update_state(States.CLOSED) elif header.ack == 1: seq_num = header.ack_num ack_num = header.seq_num + 1 syn_header = utils.Header(seq_num, ack_num, ack=1) send_udp(syn_header.bits()) self.last_seq = seq_num self.last_received_seq = header.seq_num self.last_received_ack = header.ack_num + 1 self.update_state(States.ESTABLISHED)
def handshake(self): while self.client_state != States.ESTABLISHED: if self.client_state == States.CLOSED: seq_num = utils.rand_int() self.next_seq_num = seq_num + 1 syn_header = utils.Header(seq_num, 0, syn=1, ack=0, fin=0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) self.update_state(States.SYN_SENT) elif self.client_state == States.SYN_SENT: recv_data, addr = sock.recvfrom(1024) syn_ack_header = utils.bits_to_header(recv_data) self.last_received_seq_num = syn_ack_header.seq_num if syn_ack_header.syn == 1 and syn_ack_header.ack == 1: ack_header = utils.Header(self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=0) self.next_seq_num += 1 send_udp(ack_header.bits()) self.update_state(States.ESTABLISHED) else: pass
def terminate(self): while self.client_state != States.CLOSED: if self.client_state == States.ESTABLISHED: terminate_header = utils.Header(self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=1) self.next_seq_num += 1 send_udp(terminate_header.bits()) self.update_state(States.FIN_WAIT_1) elif self.client_state == States.FIN_WAIT_1: recv_data, addr = sock.recvfrom(1024) fin_ack_header = utils.bits_to_header(recv_data) self.last_received_seq_num = fin_ack_header.seq_num if fin_ack_header.ack == 1: self.update_state(States.FIN_WAIT_2) elif self.client_state == States.FIN_WAIT_2: recv_data, addr = sock.recvfrom(1024) fin_fin_header = utils.bits_to_header(recv_data) self.last_received_seq_num = fin_fin_header.seq_num if fin_fin_header.fin == 1: terminate_ack_header = utils.Header( self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=0) self.next_seq_num += 1 send_udp(terminate_ack_header.bits()) self.update_state(States.CLOSED) else: pass
def terminate(self): if self.client_state == States.ESTABLISHED: # send FIN message fin_header = utils.Header(self.my_next_seq, 0, syn=0, ack=0, fin=1) send_udp(fin_header.bits()) # update my seq self.my_next_seq += 1 # update state self.update_state(States.FIN_WAIT_1) else: raise RuntimeError("invalid states for termination") # wait for ack if self.client_state == States.FIN_WAIT_1: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.ack == 1 and header.ack_num == self.my_next_seq: # update server seq self.server_next_seq = header.seq_num + 1 # update client state self.update_state(States.FIN_WAIT_2) else: raise RuntimeError("invalid server ack") else: raise RuntimeError("invalid states for termination") # wait for server FIN and send back a ACK if self.client_state == States.FIN_WAIT_2: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.fin == 1: # update server seq self.server_next_seq = header.seq_num + 1 # send back a ack ack_header = utils.Header(self.my_next_seq, self.server_next_seq, syn=0, ack=1, fin=0) send_udp(ack_header.bits()) # update client seq self.my_next_seq += 1 # update client state self.update_state(States.TIME_WAIT) else: raise RuntimeError("invalid server fin") else: raise RuntimeError("invalid states for termination") # wait for 2 maximum segment life time then close the client if self.client_state == States.TIME_WAIT: time.sleep(2 * MSL) self.my_next_seq = -1 self.server_next_seq = -1 self.update_state(States.CLOSED) else: raise RuntimeError("invalid states for termination")
def send_reliable_message(self, message): # divide the message into pieces according to MSS messages = [message[i:i + MSS] for i in range(0, len(message), MSS)] # send messages # we loop/wait until we receive all ack. if PROTOCOL == Protocols.STOP_AND_WAIT: current_seg = 0 while True: lra = self.last_received_ack # send one message and expect one ack header = utils.Header(self.my_next_seq, 0, syn=0, ack=0, fin=0) seg = header.bits() + messages[current_seg].encode() send_udp(seg) # receive ack for one second self.receive_acks() # received ack, update states, else, just resend the message in the next loop if lra != self.last_received_ack: self.my_next_seq += 1 current_seg += 1 # check if this is the last seg print(self.client_state) if current_seg >= len(messages): break elif PROTOCOL == Protocols.GO_BACK_N: current_seg = 0 while True: for i in range(0, SENDER_WINDOW_SIZE): if current_seg + i < len(messages): # send a full window size of messages at a time header = utils.Header(self.my_next_seq + i, 0, syn=0, ack=0, fin=0) seg = header.bits() + messages[current_seg + i].encode() send_udp(seg) # wait for acks for one second lra = self.last_received_ack self.receive_acks() # received acks, move the window if lra != self.last_received_ack: moved = self.last_received_ack - lra self.my_next_seq += moved current_seg += moved # check if this is the last seg if current_seg >= len(messages): break else: raise RuntimeError("invalid transmission protocol")
def serve(conn): data = conn.recv(1024) if not data: print '[-] Data receive error' print '[-] Exiting' sys.exit() req = pickle.loads(data) if req.header.opcode == 10 and req.header.cmd == 'PUBKEY': p = req.p g = req.g y1 = req.y1 y2 = req.y2 public_key = (g, y1, y2) print '[+] Public Key Published' print '[+] Waiting for Signed Message by Client' data = conn.recv(1024) if not data: print '[-] Data receive error' print '[-] Exiting' sys.exit() req = pickle.loads(data) if req.header.opcode == 20 and req.header.cmd == 'SIGNEDMSG': print '[+] Signed Message received' signature = req.signature c = signature.c s = signature.s msg = req.buf if verify_signature(msg, public_key, p, c, s): print '[+] Digital Signature verified successfuly' header = utils.Header(30, 'VERSTATUS') message = utils.Message(header, None, None, None, None, None, None, 'GOOD') data = pickle.dumps(message) conn.send(data) else: print '[+] Digital Signature verification failed' header = utils.Header(30, 'VERSTATUS') message = utils.Message(header, None, None, None, None, None, None, 'BAD') data = pickle.dumps(message) conn.send(data) else: print '[-] Invalid opcode or command' else: print '[-] Invalid opcode or command'
def getSharedKey(clientPort): msg = clientPort.recv(1024) msgLen = int(msg[:utils.HEADER_LENGTH]) fullMsg = msg while len(fullMsg) < msgLen: msg = clientPort.recv(1024) fullMsg += msg msgFromClient = pickle.loads(fullMsg[utils.HEADER_LENGTH:]) serverPublicKey, secret = utils.generatePublicKey( msgFromClient.publicKey.prime, msgFromClient.publicKey.root) sharedKey = utils.generateFullKey(msgFromClient.publicKey, secret) print( f"msgLength: {msgLen}, opcode: {msgFromClient.header.opcode}, prime: {msgFromClient.publicKey.prime}, root: {msgFromClient.publicKey.root}, publicKey: {msgFromClient.publicKey.pub_key}, secret: {secret}, \nShared Key: {sharedKey}" ) SetHeaderValues = utils.Header(utils.opcodeDict["PUBKEY"], socket.gethostname(), None) SetPublicKey = utils.PublicKey(msgFromClient.publicKey.prime, msgFromClient.publicKey.root, serverPublicKey.pub_key) packet = utils.Packet(SetHeaderValues, SetPublicKey, None, None, None, None) msgToSend = pickle.dumps(packet) msgToSend = bytes(f"{len(msgToSend):<{utils.HEADER_LENGTH}}", "ascii") + msgToSend clientPort.sendall(msgToSend) print("Sent public key") return sharedKey
def send_reliable_message(self, message): # send messages # we loop/wait until we receive all ack. send_byte = message.encode() pacek_total_num = int(ceil(len(send_byte) / MSS)) sent_packet_id = 0 timeout_cnt = 0 while sent_packet_id < pacek_total_num: if timeout_cnt > 2: break _this_data = send_byte[sent_packet_id * MSS:(sent_packet_id + 1) * MSS] seq_num = self.last_received_ack ack_num = self.last_received_seq + 1 self.last_seq = seq_num data_header = utils.Header(seq_num, ack_num) send_udp(data_header.bits() + _this_data) header, body, addr = recv_msg() if header is None: timeout_cnt += 1 continue if header.ack == 1 and header.ack_num == self.last_seq + len( _this_data): self.last_received_ack = header.ack_num self.last_received_seq = header.seq_num sent_packet_id += 1 timeout_cnt = 0
def sendFileReq(filename): SetHeaderValues=utils.Header(utils.opcodeDict["REQSERV"], socket.gethostname(), HOST) packet = utils.Packet(SetHeaderValues, None, utils.ReqServ(filename), None, None, None) msgToSend = pickle.dumps(packet) extract_info(10) msgToSend = bytes(f"{len(msgToSend):<{utils.HEADER_LENGTH}}", "ascii") + msgToSend sock.sendall(msgToSend)
def handshake(self): seq_num = 0 if self.client_state == States.CLOSED: seq_num = utils.rand_int() syn_header = utils.Header(seq_num, 0, 1, 0, 0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) self.update_state(States.SYN_SENT) elif self.client_state == States.SYN_SENT: header, body, addr = recv_msg() if header.syn == 1 and header.ack == 1 and header.ack_num == seq_num + 1: ack_num = header.seq_num + 1 seq_num = header.ack_num header = utils.Header(seq_num, ack_num, 0, 1, 0) send_udp(header.bits()) self.update_state(States.ESTABLISHED)
def handshake(self): if self.client_state == States.CLOSED: seq_num = utils.rand_int() syn_header = utils.Header(seq_num, 0, syn = 1, ack = 0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) self.update_state(States.SYN_SENT) else: pass
def getKeyPacket(): p = prime_generate() generatedKey, secret = utils.generatePublicKey() SetHeaderValues=utils.Header(utils.opcodeDict["PUBKEY"], socket.gethostname(), HOST) SetPublcKeyValues=utils.PublicKey(generatedKey.prime, generatedKey.root, generatedKey.pub_key) extract_info(10) packet = utils.Packet(SetHeaderValues,SetPublcKeyValues , None, None, None, None) msgToSend = pickle.dumps(packet) msgToSend = bytes(f"{len(msgToSend):<{utils.HEADER_LENGTH}}", "ascii") + msgToSend return msgToSend, secret
def terminate(self): while True: if self.client_state == States.ESTABLISHED: seq_num = utils.rand_int() header = utils.Header(seq_num, 0, 0, 0, 1) send_udp(header.bits()) self.update_state(States.FIN_WAIT_1) elif self.client_state == States.FIN_WAIT_1: header, body, addr = recv_msg() if header.ack == 1 and header.ack_num == seq_num + 1: self.update_state(States.FIN_WAIT_2) elif self.client_state == States.FIN_WAIT_2: header, body, addr = recv_msg() if header.fin == 1 and header.ack == 1 and header.ack_num == seq_num + 1: seq_num = header.ack_num ack_num = header.seq_num + 1 header = utils.Header(seq_num, ack_num, 0, 1, 0) send_udp(header.bits()) # wait for 2MSL time.sleep(1) self.update_state(States.CLOSED)
def terminate(self): if self.client_state == States.ESTABLISHED: # Step1: Client send fin message. seq_num = self.last_received_ack ack_num = self.last_received_seq + 1 fin_header = utils.Header(seq_num, ack_num, ack=1, fin=1) send_udp(fin_header.bits()) self.last_seq = seq_num self.update_state(States.FIN_WAIT_1) self.terminate() elif self.client_state == States.FIN_WAIT_1: header, body, addr = recv_msg() if header.ack == 1 and header.ack_num == self.last_seq + 1: # Step2: Recieve ack from the server and do nothing but continue waiting. # self.last_received_ack = -1 self.update_state(States.FIN_WAIT_2) self.terminate() else: self.update_state(States.ESTABLISHED) self.terminate() elif self.client_state == States.FIN_WAIT_2: # Step3: Receive fin message from server and send the last ack. # self.receive_acks() header, body, addr = recv_msg() if (header.fin == 1): seq_num = header.ack_num ack_num = header.seq_num + 1 fin_header = utils.Header(seq_num, ack_num, ack=1) send_udp(fin_header.bits()) self.last_received_seq = header.seq_num self.last_received_ack = header.ack_num self.update_state(States.TIME_WAIT) self.terminate() elif self.client_state == States.TIME_WAIT: # Step4: Wait for TIME_OUT seconds and tear down the connection. time.sleep(TIME_OUT) sock.close() self.update_state(States.CLOSED) else: pass
def handshake(self): if self.client_state == States.CLOSED: seq_num = utils.rand_int() syn_header = utils.Header(seq_num, 0, syn=1, ack=0, fin=0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) # update client seq number self.my_next_seq = seq_num + 1 self.update_state(States.SYN_SENT) else: raise RuntimeError("invalid states for start a handshake.") # we wait for server to send back a SYN-ACK message if self.client_state == States.SYN_SENT: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) # server syn header should have both syn and ack fields # and the ack_num should be client next sequence number if header.ack == 1 and header.syn == 1 and header.ack_num == self.my_next_seq: self.server_next_seq = header.seq_num + 1 self.last_received_ack = header.ack_num + 1 else: raise RuntimeError( "invalid server SYN-reply, handshake failed.") # we send back ACK message ack_header = utils.Header(self.my_next_seq, self.server_next_seq, syn=0, ack=1, fin=0) send_udp(ack_header.bits()) # update my seq self.my_next_seq += 1 # update state -> connection established on the client's perspective self.update_state(States.ESTABLISHED) else: raise RuntimeError("invalid states for waiting server SYN-reply.")
def send_reliable_message(self, message): count= 0 MSS = 2 # split the message into chunks msg = message.split() #seq number seq_num = utils.rand_int() # Create the header we attach to our message msg_header = utils.Header(seq_num, 0, syn = 0, ack = 1, fin = 0) # Send initial chunk chunk = msg[count:count + 3] chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) count += 2 while count <= 7: #handle seq / ack recv_data, addr = sock.recvfrom(1024) #receive the data sent from the server msg_header = utils.bits_to_header(recv_data) #convert received data to header format firstseq = msg_header.seq_num # first msg seq number if msg_header.seq_num == firstseq or msg_header.seq_num == subseq: #check current seq numb from previous, make sure increments by 1 chunk = msg[MSS:MSS + 3] # chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) count += 2 MSS += 2 subseq = msg_header.seq_num + 1 else: #if seq are not incrementing correctly then send previous chunk again print(msg_header.seq_num) #just printing out the seq number MSS -= 2 chunk = msg[MSS:MSS - 3] # chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) #handle stop and wait pass
def recv_msg(): data, addr = sock.recvfrom(1024) header = utils.bits_to_header(data) body = utils.get_body_from_data(data) return (header, body, addr) while True: if server_state == States.CLOSED: update_server_state(States.LISTEN) elif server_state == States.LISTEN: header, body, addr = recv_msg() last_received_seq_num = header.seq_num if header.syn == 1: seq_number = utils.rand_int() syn_ack_msg = utils.Header(seq_number, ack_num = last_received_seq_num + 1, syn = 1, ack = 1, fin = 0) seq_number += 1 sock.sendto(syn_ack_msg.bits(), addr) update_server_state(States.SYN_RECEIVED) elif server_state == States.SYN_RECEIVED: header, body, addr = recv_msg() last_received_seq_num = header.seq_num if header.ack == 1: update_server_state(States.ESTABLISHED) pass elif server_state == States.SYN_SENT: pass elif server_state == States.ESTABLISHED: header, body, addr = recv_msg() last_received_seq_num = header.seq_num if header.fin == 1:
update_server_state( States.LISTEN ) # we already started listening, just update the state elif server_state == States.LISTEN: header, body, addr = recv_msg() # waiting for a message if header is None: continue address = addr # Step1: if received message is a syn message (syn = 1, ack = 0, fin = 0), # it's a connection initiation if header.syn == 1: seq_number = utils.rand_int() # randomly pick a sequence number ack_number = header.seq_num + 1 # ack number is received sequence plus one # Step2: send ack message to client. ack_header = utils.Header(seq_number, ack_number, syn=1, ack=1) if utils.DEBUG: print("Send:") sock.sendto(ack_header.bits(), addr) update_server_state(States.SYN_RECEIVED) elif server_state == States.SYN_RECEIVED: header, body, addr = recv_msg() # waiting for the ack message # if didn't receive ack in time, stop the handshake process and go back. if header is None: update_server_state(States.CLOSE_WAIT) # Step3: if received message is the ack message from client, # we can establish the connect. if header.ack == 1: heartbeat_time = time.time() update_server_state(States.ESTABLISHED)
def serveRequest(key, clientPort): key = f"{key:<{utils.KEY_LENGTH}}" msg = clientPort.recv(1024) msgLen = int(msg[:utils.HEADER_LENGTH]) fullMsg = msg while len(fullMsg) < msgLen: msg = self.request.recv(1024) fullMsg += msg extract_info(10) msgFromClient = pickle.loads(fullMsg[utils.HEADER_LENGTH:]) filename = msgFromClient.reqServ.filename print(f"Requested file: {filename}") try: filepath = "files/" + filename with open(filepath, 'rb') as file: fileInfo = os.stat(filepath) fileSize = fileInfo.st_size # print(f"File size: {fileSize} bytes.") extract_info(10) # n=fileSize//1024 # r=fileSize%1024 # Info=FileINFO(n,r) # infopacket = pickle.dumps(Info) # clientPort.sendall(infopacket) data = file.read(1024) cipher = DES3.new(key) while len(data) > 0: blockLength = len(data) if (blockLength < 1024): rem = blockLength % 1024 if rem: data += bytes(1024 - rem) encrypted_text = cipher.encrypt(data) dec_text = cipher.decrypt(encrypted_text) SetHeadervalues = utils.Header(utils.opcodeDict["ENCMSG"], socket.gethostname(), None) packet = utils.Packet( SetHeadervalues, None, None, None, utils.EncodedMsg(encrypted_text, blockLength), None) msgToSend = pickle.dumps(packet) msgToSend = bytes(f"{len(msgToSend):<{utils.HEADER_LENGTH}}", "ascii") + msgToSend # print("s:,", len(msgToSend)) clientPort.sendall(msgToSend) data = file.read(1024) extract_info(10) SetHeadervalues = utils.Header(utils.opcodeDict["REQCOM"], socket.gethostname(), None) packet = utils.Packet(SetHeadervalues, None, None, utils.ReqComp(400), None, None) msgToSend = pickle.dumps(packet) msgToSend = bytes(f"{len(msgToSend):<{utils.HEADER_LENGTH}}", "ascii") + msgToSend clientPort.sendall(msgToSend) print("file sent") except FileNotFoundError: print("File not found") extract_info(10) packet = utils.Packet( utils.Header(utils.opcodeDict["DISCONNECT"], socket.gethostname(), None), None, None, None, None, utils.Disconnect()) msgToSend = pickle.dumps(packet) clientPort.sendall(msgToSend)
if __name__ == '__main__': soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print '[+] Starting Client' soc.connect((utils.ip, utils.port)) print '[+] Connected to Server' print '[+] Generating Public Key' private_key, public_key, p = generate_key() print '[+] Publishing Public Key' g = public_key[0] y1 = public_key[1] y2 = public_key[2] header = utils.Header(10, 'PUBKEY') message = utils.Message(header, p, g, y1, y2, None, None, None) data = pickle.dumps(message) soc.send(data) print '[+] Public Key sent to Server' msg = raw_input('Enter message: ') print '[+] Generating Signature' c, s = generate_signature(msg, private_key, public_key, p) print '[+] Signature generated' header = utils.Header(20, 'SIGNEDMSG') signature = utils.Signature(c, s) message = utils.Message(header, p, g, y1, y2, msg, signature, None) data = pickle.dumps(message) print '[+] Sending signed message to server'
# we are waiting for a message header, body, addr = recv_msg() # if received message is a syn message, it's a connection # initiation if header.syn == 1: # update seq numbers my_next_seq = utils.rand_int( ) # we randomly pick a sequence number client_next_seq = header.seq_num + 1 # update client addr client_addr = addr # make a syn-ack header and send to to client syn_ack_header = utils.Header(my_next_seq, client_next_seq, syn=1, ack=1, fin=0) sock.sendto(syn_ack_header.bits(), client_addr) # update my seq number my_next_seq += 1 # update server state update_server_state(States.SYN_RECEIVED) else: # discard non-SYN messages pass elif server_state == States.SYN_RECEIVED: # we are waiting for a message header, body, addr = recv_msg() # we only receive message from our client addr
# we are waiting for a message header, body, addr = recv_msg() # if received message is a syn message, it's a connection # initiation if header.syn == 1: seq_number = utils.rand_int() # we randomly pick a sequence number ack_number = header.seq_num + 1 # to be implemented update_server_state(States.SYN_RECEIVED) ### sending message from the server: # use the following method to send messages back to client # addr is recieved when we receive a message from a client (see above) # sock.sendto(your_header_object.bits(), addr) elif server_state == States.SYN_RECEIVED: header = utils.Header(seq_number, ack_number, 1, 1, 0) sock.sendto(header.bits(), addr) update_server_state(States.SYN_SENT) elif server_state == States.SYN_SENT: header, body, addr2 = recv_msg() if addr == addr2 and header.ack == 1 and header.ack_num == seq_number + 1: update_server_state(States.ESTABLISHED) # if we never met such respond message, it will stuck here, we need a time limit to quit the state elif server_state == States.ESTABLISHED: header, body, addr3 = recv_msg() if addr == addr3 and header.fin == 1: seq_number = utils.rand_int() # we randomly pick a sequence number ack_number = header.seq_num + 1 update_server_state(States.FIN_RCVD) elif server_state == States.FIN_RCVD: header = utils.Header(seq_number, ack_number, 0, 1, 0)