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,7 @@ 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 ) / UDP ( sport = sa_ll [ 1 ], dport = self . port ) / CoAP (bytes (pkt ))
576599 if pkt :
577600 if not self ._debug_drop_package ():
578601 self ._on_pkt_recv (pkt , sa_ll )
@@ -629,15 +652,16 @@ def _delete(self, resource):
629652 def _handle_rcv_request (self , pkt , sa_ll ):
630653 # type: (CoAP, tuple[str, int]) -> None
631654 """Process a received request"""
655+ coap_pkt = pkt [CoAP ]
632656 req_uri = "/"
633- token = int .from_bytes (pkt .token , "big" ) # Can be up to 8 bytes
634- message_id = pkt .msg_id
657+ token = int .from_bytes (coap_pkt .token , "big" ) # Can be up to 8 bytes
658+ message_id = coap_pkt .msg_id
635659 lst_options = []
636660 response = {"type" : ACK , "code" : NOT_FOUND_404 ,
637661 "options" : [(CONTENT_FORMAT , CF_TEXT_PLAIN )],
638662 "payload" : coap_codes [NOT_FOUND_404 ].encode ("utf8" )}
639663
640- for option in pkt .options :
664+ for option in coap_pkt .options :
641665 option_type_id = coap_options [1 ].get (option [0 ], - 1 )
642666 option_value = option [1 ]
643667
@@ -658,14 +682,14 @@ def _handle_rcv_request(self, pkt, sa_ll):
658682 resource = self .resources .get (req_uri , None )
659683 if resource is not None :
660684 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 :
685+ if coap_pkt .code == GET :
686+ response = resource .get (coap_pkt .payload , lst_options , token , sa_ll )
687+ elif coap_pkt .code == POST :
664688 # @todo: handle existing resource POST: RFC 7252 @ section-5.8.2
665689 pass
666- elif pkt .code == PUT :
667- response = resource .put (pkt .payload , lst_options , token , sa_ll )
668- elif pkt .code == DELETE :
690+ elif coap_pkt .code == PUT :
691+ response = resource .put (coap_pkt .payload , lst_options , token , sa_ll )
692+ elif coap_pkt .code == DELETE :
669693 response = self ._delete (resource )
670694
671695 resource ._register_request_response (message_id , token , response )
@@ -677,16 +701,16 @@ def _handle_rcv_request(self, pkt, sa_ll):
677701 req_uri ,
678702 message_id , token )
679703 else :
680- if pkt .code == POST :
704+ if coap_pkt .code == POST :
681705 response = self ._post ()
682706 else :
683707 log_coap_sock .warning ("Unknown resource: URI=%s" , req_uri )
684708
685- response ["tkl" ] = pkt .tkl
686- response ["token" ] = pkt .token
709+ response ["tkl" ] = coap_pkt .tkl
710+ response ["token" ] = coap_pkt .token
687711 response ["msg_id" ] = message_id
688712
689- if pkt .type == NON :
713+ if coap_pkt .type == NON :
690714 response ["type" ] = NON
691715
692716 # Add paymark (separator between options and payload)
@@ -751,13 +775,14 @@ def _handle_request_response(self, pkt, sa_ll):
751775 Handles a received response. Will check if there is the valid request.
752776 Otherwise, it will put in the rx_queue for the user to handle it
753777 via the recv() function.
754- :param pkt : The CoAP packet to be processed
778+ :param coap_pkt : The CoAP packet to be processed
755779 :param sa_ll: The ip/port tuple of the sender
756780 """
757- token = int .from_bytes (pkt .token , "big" )
758- index = (pkt .msg_id , token )
781+ coap_pkt = pkt [CoAP ]
782+ token = int .from_bytes (coap_pkt .token , "big" )
783+ index = (coap_pkt .msg_id , token )
759784 request = self .pending_requests .get (index , None )
760- if request is None and (pkt .type == ACK or pkt .type == CON or pkt .type == NON ):
785+ if request is None and (coap_pkt .type == ACK or coap_pkt .type == CON or coap_pkt .type == NON ):
761786 for key in self .pending_requests .keys ():
762787 if index [0 ] == key [0 ] or index [1 ] == key [1 ]:
763788 log_coap_sock .info ("Found request by using %s" ,
@@ -770,38 +795,40 @@ def _handle_request_response(self, pkt, sa_ll):
770795 if request is None :
771796 log_coap_sock .warning (
772797 "Request for received response not found: msg_id=%s; token=0x%x" ,
773- pkt .msg_id , token )
798+ coap_pkt .msg_id , token )
774799 return
775800
776- if pkt .type == ACK and pkt .code != EMPTY_MESSAGE :
801+ if coap_pkt .type == ACK and coap_pkt .code != EMPTY_MESSAGE :
777802 log_coap_sock .debug ("Request fulfilled: msg_id=%s; token=0x%x; code=%s" ,
778803 index [0 ], index [1 ],
779- coap_codes [pkt .code ])
804+ coap_codes [coap_pkt .code ])
805+ pkt .sport = self .pending_requests [index ].port
780806 del self .pending_requests [index ]
781- self .rx_queue .send ((pkt .build (), pkt .time ))
782- elif pkt .type == ACK and pkt .code == EMPTY_MESSAGE :
807+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
808+ elif coap_pkt .type == ACK and coap_pkt .code == EMPTY_MESSAGE :
783809 log_coap_sock .debug (
784810 "Server sent an empty ack, request will be fulfilled later: "
785811 "msg_id=%s; token=0x%x; code=%s" ,
786- index [0 ], index [1 ], coap_codes [pkt .code ])
812+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
787813 request .empty_ack_set ()
788- elif pkt .type == CON and pkt .code == CONTENT_205 :
814+ elif coap_pkt .type == CON and coap_pkt .code == CONTENT_205 :
789815 log_coap_sock .debug (
790816 "Received a delayed content for a previous request: msg_id=%s; "
791817 "token=0x%x; code=%s" ,
792- index [0 ], index [1 ], coap_codes [pkt .code ])
818+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
793819
794820 # We need to respond with an empty ACK
795821 request .empty_ack_fulfilled = True
796822 response = CoAPSocketImpl .empty_ack_params ()
797- response ["msg_id" ] = pkt .msg_id
823+ response ["msg_id" ] = coap_pkt .msg_id
798824 self ._sock_send (sa_ll , CoAP (** response ))
799- self .rx_queue .send ((pkt .build (), pkt .time ))
825+ pkt .sport = request .port
826+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
800827 else :
801828 log_coap_sock .info ("Not handled message: "
802829 "type=%s; code=%s;" ,
803- pkt .type , coap_codes [pkt .code ])
804- self .rx_queue .send ((pkt .build (), pkt .time ))
830+ coap_pkt .type , coap_codes [coap_pkt .code ])
831+ self .rx_queue .send ((pkt .build (), coap_pkt .time ))
805832
806833 def _sock_send (self , address , pl ):
807834 # type: (tuple[str, int], Packet) -> None
0 commit comments