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,9 @@ 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 ) /
599
+ UDP (sport = sa_ll [1 ], dport = self .port ) /
600
+ CoAP (bytes (pkt )))
576
601
if pkt :
577
602
if not self ._debug_drop_package ():
578
603
self ._on_pkt_recv (pkt , sa_ll )
@@ -629,15 +654,16 @@ def _delete(self, resource):
629
654
def _handle_rcv_request (self , pkt , sa_ll ):
630
655
# type: (CoAP, tuple[str, int]) -> None
631
656
"""Process a received request"""
657
+ coap_pkt = pkt [CoAP ]
632
658
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
635
661
lst_options = []
636
662
response = {"type" : ACK , "code" : NOT_FOUND_404 ,
637
663
"options" : [(CONTENT_FORMAT , CF_TEXT_PLAIN )],
638
664
"payload" : coap_codes [NOT_FOUND_404 ].encode ("utf8" )}
639
665
640
- for option in pkt .options :
666
+ for option in coap_pkt .options :
641
667
option_type_id = coap_options [1 ].get (option [0 ], - 1 )
642
668
option_value = option [1 ]
643
669
@@ -658,14 +684,14 @@ def _handle_rcv_request(self, pkt, sa_ll):
658
684
resource = self .resources .get (req_uri , None )
659
685
if resource is not None :
660
686
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 :
664
690
# @todo: handle existing resource POST: RFC 7252 @ section-5.8.2
665
691
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 :
669
695
response = self ._delete (resource )
670
696
671
697
resource ._register_request_response (message_id , token , response )
@@ -677,16 +703,16 @@ def _handle_rcv_request(self, pkt, sa_ll):
677
703
req_uri ,
678
704
message_id , token )
679
705
else :
680
- if pkt .code == POST :
706
+ if coap_pkt .code == POST :
681
707
response = self ._post ()
682
708
else :
683
709
log_coap_sock .warning ("Unknown resource: URI=%s" , req_uri )
684
710
685
- response ["tkl" ] = pkt .tkl
686
- response ["token" ] = pkt .token
711
+ response ["tkl" ] = coap_pkt .tkl
712
+ response ["token" ] = coap_pkt .token
687
713
response ["msg_id" ] = message_id
688
714
689
- if pkt .type == NON :
715
+ if coap_pkt .type == NON :
690
716
response ["type" ] = NON
691
717
692
718
# Add paymark (separator between options and payload)
@@ -751,13 +777,15 @@ def _handle_request_response(self, pkt, sa_ll):
751
777
Handles a received response. Will check if there is the valid request.
752
778
Otherwise, it will put in the rx_queue for the user to handle it
753
779
via the recv() function.
754
- :param pkt : The CoAP packet to be processed
780
+ :param coap_pkt : The CoAP packet to be processed
755
781
:param sa_ll: The ip/port tuple of the sender
756
782
"""
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 )
759
786
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 )):
761
789
for key in self .pending_requests .keys ():
762
790
if index [0 ] == key [0 ] or index [1 ] == key [1 ]:
763
791
log_coap_sock .info ("Found request by using %s" ,
@@ -770,38 +798,40 @@ def _handle_request_response(self, pkt, sa_ll):
770
798
if request is None :
771
799
log_coap_sock .warning (
772
800
"Request for received response not found: msg_id=%s; token=0x%x" ,
773
- pkt .msg_id , token )
801
+ coap_pkt .msg_id , token )
774
802
return
775
803
776
- if pkt .type == ACK and pkt .code != EMPTY_MESSAGE :
804
+ if coap_pkt .type == ACK and coap_pkt .code != EMPTY_MESSAGE :
777
805
log_coap_sock .debug ("Request fulfilled: msg_id=%s; token=0x%x; code=%s" ,
778
806
index [0 ], index [1 ],
779
- coap_codes [pkt .code ])
807
+ coap_codes [coap_pkt .code ])
808
+ pkt .sport = self .pending_requests [index ].port
780
809
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 :
783
812
log_coap_sock .debug (
784
813
"Server sent an empty ack, request will be fulfilled later: "
785
814
"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 ])
787
816
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 :
789
818
log_coap_sock .debug (
790
819
"Received a delayed content for a previous request: msg_id=%s; "
791
820
"token=0x%x; code=%s" ,
792
- index [0 ], index [1 ], coap_codes [pkt .code ])
821
+ index [0 ], index [1 ], coap_codes [coap_pkt .code ])
793
822
794
823
# We need to respond with an empty ACK
795
824
request .empty_ack_fulfilled = True
796
825
response = CoAPSocketImpl .empty_ack_params ()
797
- response ["msg_id" ] = pkt .msg_id
826
+ response ["msg_id" ] = coap_pkt .msg_id
798
827
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 ))
800
830
else :
801
831
log_coap_sock .info ("Not handled message: "
802
832
"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 ))
805
835
806
836
def _sock_send (self , address , pl ):
807
837
# type: (tuple[str, int], Packet) -> None
0 commit comments