30
30
from scapy .data import MTU
31
31
from scapy .utils import EDecimal
32
32
from scapy .automaton import ObjectPipe , select_objects
33
-
33
+ from scapy . layers . inet import UDP , IP
34
34
from scapy .supersocket import SuperSocket , SimpleSocket
35
35
36
36
log_coap_sock = logging .getLogger ("scapy.contrib.coap_socket" )
@@ -123,8 +123,8 @@ def recv_raw(self, x=0xffff):
123
123
if not self .closed :
124
124
tup = self .impl .recv ()
125
125
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
128
128
129
129
def recv (self , x = MTU , ** kwargs ):
130
130
# type: (int, **Any) -> Optional[Packet]
@@ -152,6 +152,29 @@ def send(self, x):
152
152
self .impl .send (x .dst , x .dport , x [CoAP ])
153
153
return len (x )
154
154
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
+
155
178
@staticmethod
156
179
def make_coap_req_packet (method = GET , uri = "" , options = None , payload = b"" ):
157
180
# type: (int, str, list[tuple], bytes) -> Packet
@@ -572,7 +595,7 @@ def _recv(self):
572
595
573
596
if self .sock .select ([self .sock ], 0 ):
574
597
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 ))
576
599
if pkt :
577
600
if not self ._debug_drop_package ():
578
601
self ._on_pkt_recv (pkt , sa_ll )
@@ -629,15 +652,16 @@ def _delete(self, resource):
629
652
def _handle_rcv_request (self , pkt , sa_ll ):
630
653
# type: (CoAP, tuple[str, int]) -> None
631
654
"""Process a received request"""
655
+ coap_pkt = pkt [CoAP ]
632
656
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
635
659
lst_options = []
636
660
response = {"type" : ACK , "code" : NOT_FOUND_404 ,
637
661
"options" : [(CONTENT_FORMAT , CF_TEXT_PLAIN )],
638
662
"payload" : coap_codes [NOT_FOUND_404 ].encode ("utf8" )}
639
663
640
- for option in pkt .options :
664
+ for option in coap_pkt .options :
641
665
option_type_id = coap_options [1 ].get (option [0 ], - 1 )
642
666
option_value = option [1 ]
643
667
@@ -658,14 +682,14 @@ def _handle_rcv_request(self, pkt, sa_ll):
658
682
resource = self .resources .get (req_uri , None )
659
683
if resource is not None :
660
684
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 :
664
688
# @todo: handle existing resource POST: RFC 7252 @ section-5.8.2
665
689
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 :
669
693
response = self ._delete (resource )
670
694
671
695
resource ._register_request_response (message_id , token , response )
@@ -677,16 +701,16 @@ def _handle_rcv_request(self, pkt, sa_ll):
677
701
req_uri ,
678
702
message_id , token )
679
703
else :
680
- if pkt .code == POST :
704
+ if coap_pkt .code == POST :
681
705
response = self ._post ()
682
706
else :
683
707
log_coap_sock .warning ("Unknown resource: URI=%s" , req_uri )
684
708
685
- response ["tkl" ] = pkt .tkl
686
- response ["token" ] = pkt .token
709
+ response ["tkl" ] = coap_pkt .tkl
710
+ response ["token" ] = coap_pkt .token
687
711
response ["msg_id" ] = message_id
688
712
689
- if pkt .type == NON :
713
+ if coap_pkt .type == NON :
690
714
response ["type" ] = NON
691
715
692
716
# Add paymark (separator between options and payload)
@@ -751,13 +775,14 @@ def _handle_request_response(self, pkt, sa_ll):
751
775
Handles a received response. Will check if there is the valid request.
752
776
Otherwise, it will put in the rx_queue for the user to handle it
753
777
via the recv() function.
754
- :param pkt : The CoAP packet to be processed
778
+ :param coap_pkt : The CoAP packet to be processed
755
779
:param sa_ll: The ip/port tuple of the sender
756
780
"""
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 )
759
784
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 ):
761
786
for key in self .pending_requests .keys ():
762
787
if index [0 ] == key [0 ] or index [1 ] == key [1 ]:
763
788
log_coap_sock .info ("Found request by using %s" ,
@@ -770,38 +795,40 @@ def _handle_request_response(self, pkt, sa_ll):
770
795
if request is None :
771
796
log_coap_sock .warning (
772
797
"Request for received response not found: msg_id=%s; token=0x%x" ,
773
- pkt .msg_id , token )
798
+ coap_pkt .msg_id , token )
774
799
return
775
800
776
- if pkt .type == ACK and pkt .code != EMPTY_MESSAGE :
801
+ if coap_pkt .type == ACK and coap_pkt .code != EMPTY_MESSAGE :
777
802
log_coap_sock .debug ("Request fulfilled: msg_id=%s; token=0x%x; code=%s" ,
778
803
index [0 ], index [1 ],
779
- coap_codes [pkt .code ])
804
+ coap_codes [coap_pkt .code ])
805
+ pkt .sport = self .pending_requests [index ].port
780
806
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 :
783
809
log_coap_sock .debug (
784
810
"Server sent an empty ack, request will be fulfilled later: "
785
811
"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 ])
787
813
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 :
789
815
log_coap_sock .debug (
790
816
"Received a delayed content for a previous request: msg_id=%s; "
791
817
"token=0x%x; code=%s" ,
792
- index [0 ], index [1 ], coap_codes [pkt .code ])
818
+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
793
819
794
820
# We need to respond with an empty ACK
795
821
request .empty_ack_fulfilled = True
796
822
response = CoAPSocketImpl .empty_ack_params ()
797
- response ["msg_id" ] = pkt .msg_id
823
+ response ["msg_id" ] = coap_pkt .msg_id
798
824
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 ))
800
827
else :
801
828
log_coap_sock .info ("Not handled message: "
802
829
"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 ))
805
832
806
833
def _sock_send (self , address , pl ):
807
834
# type: (tuple[str, int], Packet) -> None
0 commit comments