|
From: <don...@is...> - 2008-12-29 18:02:47
|
Sam Steingold writes: > > I also have code for doing it from lisp if you have rawsock. > > Let me know if you want to go down that path. > yes, please. > I want the code that would let me debug this without an external > telnet. i.e., clisp should open the connection, kill it, and send a > reset. I'm trying to make this as simple as possible, but you'll see it's really not there. I actually spent way too much time on this trying to figure out what I was doing wrong before I discovered that it behaved as I expected over the net but not for communication within one machine (localhost). I still don't understand why that is, but I suggest you do the testing on two different machines as described below. It could be related to the OS version, in this case both machines are FC4: Linux don-eve.dyndns.org 2.6.17-1.2142_FC4 #1 Tue Jul 11 22:41:14 EDT 2006 i686 i686 i386 GNU/Linux BTW, as part of my search I started to suspect the checksum routines and I did find a few small problems with them. More on that later... Anyhow, here's my demo: The code I'm sending uses rawsock, so of course you need a clisp built with rawsock. And you have to be root to use it. On the server machine (where you'll be adding gdb to what I do): run lisp [1]> (setf ss (socket:socket-server 1234 :interface "64.27.16.100")) 64.27.16.100 => ip address of your server, not 127.0.0.1 Same substitution applies below. #<SOCKET-SERVER 64.27.16.100:1234> [2]> (setf str (socket:socket-accept ss)) on the client machine as root run clisp with rawsock (load "reset.lisp") ;; provided below (waitforpkt '(64 27 16 100) 1234) This is likely to print some *'s to show you that it sees packets other than what it's waiting for. Now in another process on the same client machine $ telnet 64.27.16.100 1234 Trying 64.27.16.100... Connected to 64.27.16.100 (64.27.16.100). Escape character is '^]'. This should cause the other two lisp processes that are waiting for relevant packets to return. server: [3]> client: ... ***** T [2]> now you can send the reset from the client lisp process: [2]> (reset) and now on the server I get this [3]> (socket:socket-status str) [../src/stream.d:6143] *** - UNIX error 104 (ECONNRESET): Connection reset by peer The following restarts are available: ABORT :R1 Abort main loop Break 1 [4]> By the way, at this point you can now return to the telnet and simply type enter to get this: Connection closed by foreign host. ==== reset.lisp (defvar default-socket (rawsock:socket :inet :packet #+ignore :all #x300)) (unless (> default-socket 0) (error "socket failed - running as root?")) (defvar default-buffer (make-array 1518 :element-type '(unsigned-byte 8) :fill-pointer 100)) (defvar default-device (rawsock:make-sockaddr :packet (make-array 14 :element-type '(unsigned-byte 8)))) (defun waitforpkt(serverip serverport &key (show 100)) (loop for i from 0 with len do (setf (fill-pointer default-buffer) 1518) (setf len (rawsock:recvfrom default-socket default-buffer default-device)) (when (= 0 (mod i show))(princ "*")) (when (and (>= len 52) (= (aref default-buffer 12) 8) ;; ip (= (aref default-buffer 13) 0) (= (aref default-buffer 14) 69) ;; ipv4, len 5 (= (aref default-buffer 23) 6) ;; tcp (loop for j from 0 as a in serverip always (= a (aref default-buffer (+ j 30)))) ;; correct ip addr (= serverport (+ (aref default-buffer 37) (* 256 (aref default-buffer 36)))) (= 16 (aref default-buffer 47))) (return t)))) (defun reset() ;; change flags to from ack to rst+ack (setf (aref default-buffer 47) 20) (setf (aref default-buffer 46) 80) ;tcp header length = 5 words ;; set buffer length (setf (fill-pointer default-buffer) 54) ;; 60 ?? (setf (aref default-buffer 17) 40) (rawsock:tcpcsum default-buffer) ;; not returning right answer? (setf ipc (rawsock:ipcsum default-buffer)) ;; returns bytes reversed? (rawsock:sendto default-socket default-buffer default-device)) #| (waitforpkt '(64 27 16 100) 1234) (reset) |# |