3030from scapy .data import MTU
3131from scapy .utils import EDecimal
3232from scapy .automaton import ObjectPipe , select_objects
33-
33+ from scapy . layers . inet import UDP , IP
3434from scapy .supersocket import SuperSocket , SimpleSocket
3535
3636log_coap_sock = logging .getLogger ("scapy.contrib.coap_socket" )
@@ -123,8 +123,8 @@ def recv_raw(self, x=0xffff):
123123 if not self .closed :
124124 tup = self .impl .recv ()
125125 if tup is not None :
126- return self . basecls , tup [0 ], float (tup [1 ])
127- return self . basecls , None , None
126+ return IP , tup [0 ], float (tup [1 ])
127+ return IP , None , None
128128
129129 def recv (self , x = MTU , ** kwargs ):
130130 # type: (int, **Any) -> Optional[Packet]
@@ -152,6 +152,29 @@ def send(self, x):
152152 self .impl .send (x .dst , x .dport , x [CoAP ])
153153 return len (x )
154154
155+ def sr (self , * args , ** kargs ):
156+ args [0 ].sport = self .impl .port
157+ return super (CoAPSocket , self ).sr (* args , ** kargs )
158+
159+ def sr1 (self , * args , ** kargs ):
160+ args [0 ].sport = self .impl .port
161+ return super (CoAPSocket , self ).sr1 (* args , ** kargs )
162+
163+ @staticmethod
164+ def select (sockets , remain = None ):
165+ # type: (list[SuperSocket], Optional[float]) -> list[SuperSocket]
166+ """
167+ This function is called during sendrecv() routine to wait for
168+ sockets to be ready to receive.
169+ """
170+ obj_pipes = [x .impl .rx_queue for x in sockets if
171+ isinstance (x , CoAPSocket ) and not x .closed ]
172+
173+ ready_pipes = select_objects (obj_pipes , 0 )
174+
175+ return [x for x in sockets if isinstance (x , CoAPSocket ) and
176+ not x .closed and x .impl .rx_queue in ready_pipes ]
177+
155178 @staticmethod
156179 def make_coap_req_packet (method = GET , uri = "" , options = None , payload = b"" ):
157180 # type: (int, str, list[tuple], bytes) -> Packet
@@ -572,7 +595,9 @@ def _recv(self):
572595
573596 if self .sock .select ([self .sock ], 0 ):
574597 pkt , sa_ll = self .sock .ins .recvfrom (MTU )
575- pkt = CoAP (bytes (pkt ))
598+ pkt = (IP (src = sa_ll [0 ], dst = self .ip ) /
599+ UDP (sport = sa_ll [1 ], dport = self .port ) /
600+ CoAP (bytes (pkt )))
576601 if pkt :
577602 if not self ._debug_drop_package ():
578603 self ._on_pkt_recv (pkt , sa_ll )
@@ -629,15 +654,16 @@ def _delete(self, resource):
629654 def _handle_rcv_request (self , pkt , sa_ll ):
630655 # type: (CoAP, tuple[str, int]) -> None
631656 """Process a received request"""
657+ coap_pkt = pkt [CoAP ]
632658 req_uri = "/"
633- token = int .from_bytes (pkt .token , "big" ) # Can be up to 8 bytes
634- message_id = pkt .msg_id
659+ token = int .from_bytes (coap_pkt .token , "big" ) # Can be up to 8 bytes
660+ message_id = coap_pkt .msg_id
635661 lst_options = []
636662 response = {"type" : ACK , "code" : NOT_FOUND_404 ,
637663 "options" : [(CONTENT_FORMAT , CF_TEXT_PLAIN )],
638664 "payload" : coap_codes [NOT_FOUND_404 ].encode ("utf8" )}
639665
640- for option in pkt .options :
666+ for option in coap_pkt .options :
641667 option_type_id = coap_options [1 ].get (option [0 ], - 1 )
642668 option_value = option [1 ]
643669
@@ -658,14 +684,14 @@ def _handle_rcv_request(self, pkt, sa_ll):
658684 resource = self .resources .get (req_uri , None )
659685 if resource is not None :
660686 if not resource .check_duplicated (message_id , token ):
661- if pkt .code == GET :
662- response = resource .get (pkt .payload , lst_options , token , sa_ll )
663- elif pkt .code == POST :
687+ if coap_pkt .code == GET :
688+ response = resource .get (coap_pkt .payload , lst_options , token , sa_ll )
689+ elif coap_pkt .code == POST :
664690 # @todo: handle existing resource POST: RFC 7252 @ section-5.8.2
665691 pass
666- elif pkt .code == PUT :
667- response = resource .put (pkt .payload , lst_options , token , sa_ll )
668- elif pkt .code == DELETE :
692+ elif coap_pkt .code == PUT :
693+ response = resource .put (coap_pkt .payload , lst_options , token , sa_ll )
694+ elif coap_pkt .code == DELETE :
669695 response = self ._delete (resource )
670696
671697 resource ._register_request_response (message_id , token , response )
@@ -677,16 +703,16 @@ def _handle_rcv_request(self, pkt, sa_ll):
677703 req_uri ,
678704 message_id , token )
679705 else :
680- if pkt .code == POST :
706+ if coap_pkt .code == POST :
681707 response = self ._post ()
682708 else :
683709 log_coap_sock .warning ("Unknown resource: URI=%s" , req_uri )
684710
685- response ["tkl" ] = pkt .tkl
686- response ["token" ] = pkt .token
711+ response ["tkl" ] = coap_pkt .tkl
712+ response ["token" ] = coap_pkt .token
687713 response ["msg_id" ] = message_id
688714
689- if pkt .type == NON :
715+ if coap_pkt .type == NON :
690716 response ["type" ] = NON
691717
692718 # Add paymark (separator between options and payload)
@@ -751,13 +777,15 @@ def _handle_request_response(self, pkt, sa_ll):
751777 Handles a received response. Will check if there is the valid request.
752778 Otherwise, it will put in the rx_queue for the user to handle it
753779 via the recv() function.
754- :param pkt : The CoAP packet to be processed
780+ :param coap_pkt : The CoAP packet to be processed
755781 :param sa_ll: The ip/port tuple of the sender
756782 """
757- token = int .from_bytes (pkt .token , "big" )
758- index = (pkt .msg_id , token )
783+ coap_pkt = pkt [CoAP ]
784+ token = int .from_bytes (coap_pkt .token , "big" )
785+ index = (coap_pkt .msg_id , token )
759786 request = self .pending_requests .get (index , None )
760- if request is None and (pkt .type == ACK or pkt .type == CON or pkt .type == NON ):
787+ if (request is None and
788+ (coap_pkt .type == ACK or coap_pkt .type == CON or coap_pkt .type == NON )):
761789 for key in self .pending_requests .keys ():
762790 if index [0 ] == key [0 ] or index [1 ] == key [1 ]:
763791 log_coap_sock .info ("Found request by using %s" ,
@@ -770,38 +798,40 @@ def _handle_request_response(self, pkt, sa_ll):
770798 if request is None :
771799 log_coap_sock .warning (
772800 "Request for received response not found: msg_id=%s; token=0x%x" ,
773- pkt .msg_id , token )
801+ coap_pkt .msg_id , token )
774802 return
775803
776- if pkt .type == ACK and pkt .code != EMPTY_MESSAGE :
804+ if coap_pkt .type == ACK and coap_pkt .code != EMPTY_MESSAGE :
777805 log_coap_sock .debug ("Request fulfilled: msg_id=%s; token=0x%x; code=%s" ,
778806 index [0 ], index [1 ],
779- coap_codes [pkt .code ])
807+ coap_codes [coap_pkt .code ])
808+ pkt .sport = self .pending_requests [index ].port
780809 del self .pending_requests [index ]
781- self .rx_queue .send ((pkt .build (), pkt .time ))
782- elif pkt .type == ACK and pkt .code == EMPTY_MESSAGE :
810+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
811+ elif coap_pkt .type == ACK and coap_pkt .code == EMPTY_MESSAGE :
783812 log_coap_sock .debug (
784813 "Server sent an empty ack, request will be fulfilled later: "
785814 "msg_id=%s; token=0x%x; code=%s" ,
786- index [0 ], index [1 ], coap_codes [pkt .code ])
815+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
787816 request .empty_ack_set ()
788- elif pkt .type == CON and pkt .code == CONTENT_205 :
817+ elif coap_pkt .type == CON and coap_pkt .code == CONTENT_205 :
789818 log_coap_sock .debug (
790819 "Received a delayed content for a previous request: msg_id=%s; "
791820 "token=0x%x; code=%s" ,
792- index [0 ], index [1 ], coap_codes [pkt .code ])
821+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
793822
794823 # We need to respond with an empty ACK
795824 request .empty_ack_fulfilled = True
796825 response = CoAPSocketImpl .empty_ack_params ()
797- response ["msg_id" ] = pkt .msg_id
826+ response ["msg_id" ] = coap_pkt .msg_id
798827 self ._sock_send (sa_ll , CoAP (** response ))
799- self .rx_queue .send ((pkt .build (), pkt .time ))
828+ pkt .sport = request .port
829+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
800830 else :
801831 log_coap_sock .info ("Not handled message: "
802832 "type=%s; code=%s;" ,
803- pkt .type , coap_codes [pkt .code ])
804- self .rx_queue .send ((pkt .build (), pkt .time ))
833+ coap_pkt .type , coap_codes [coap_pkt .code ])
834+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
805835
806836 def _sock_send (self , address , pl ):
807837 # type: (tuple[str, int], Packet) -> None
0 commit comments