reverse up until test 4
Finally fixed ignoring bad packets. Next is long lines
This commit is contained in:
parent
7d1069cf2c
commit
9f6a251ceb
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
logs
|
24
analyze/reverse.py
Normal file
24
analyze/reverse.py
Normal file
@ -0,0 +1,24 @@
|
||||
import sys
|
||||
|
||||
ses = {}
|
||||
|
||||
fil = open(sys.argv[1])
|
||||
for l in fil:
|
||||
l = l.strip()
|
||||
p = l.split("]")
|
||||
tst = p[1][2:]
|
||||
txt = p[2].strip()
|
||||
tp = txt.split(" ")
|
||||
print(txt)
|
||||
if txt.startswith("NOTE:successfully connected with session"):
|
||||
sid = int(tp[-1])
|
||||
ses[sid] = [sid, tst, False]
|
||||
if txt.startswith("NOTE:closed session"):
|
||||
sid = int(tp[2])
|
||||
ses[sid][2] = True
|
||||
print("unclosed sessions:")
|
||||
for v in ses.values():
|
||||
if v[2] == False:
|
||||
print(v[1], v[0])
|
||||
|
||||
|
4
main.go
4
main.go
@ -12,7 +12,7 @@ type Server interface {
|
||||
|
||||
func main() {
|
||||
var challenge int
|
||||
flag.IntVar(&challenge, "challenge",6, "Challenge number")
|
||||
flag.IntVar(&challenge, "challenge",7, "Challenge number")
|
||||
flag.Parse()
|
||||
|
||||
var port uint16
|
||||
@ -33,6 +33,8 @@ func main() {
|
||||
server = NewProxyServer(port);
|
||||
case 6:
|
||||
server = NewSpeedServer(port);
|
||||
case 7:
|
||||
server = NewReverseServer(port);
|
||||
default:
|
||||
fmt.Printf("Unknown challenge\n")
|
||||
os.Exit(1)
|
||||
|
435
reverse.go
Normal file
435
reverse.go
Normal file
@ -0,0 +1,435 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"fmt"
|
||||
"os"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"time"
|
||||
)
|
||||
|
||||
const MAXPACKET = 999
|
||||
|
||||
func b(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func Min(a uint32, b uint32) uint32 {
|
||||
if a < b { return a}
|
||||
return b
|
||||
}
|
||||
|
||||
func Max(a uint32, b uint32) uint32 {
|
||||
if a > b { return a}
|
||||
return b
|
||||
}
|
||||
|
||||
func b2i(s []byte) (uint32, error) {
|
||||
var num uint32
|
||||
_, err := fmt.Sscanf(string(s), "%d", &num)
|
||||
return num, err
|
||||
}
|
||||
|
||||
func reverse(s []byte) []byte{
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func splitSlash(s []byte) ([]byte, []byte) {
|
||||
parts := bytes.SplitAfterN(s, b("/"), 2)
|
||||
if len(parts) != 2 {
|
||||
return b(""),b("")
|
||||
}
|
||||
p := parts[0]
|
||||
return p[:len(p)-1], parts[1]
|
||||
}
|
||||
|
||||
func calcMaxEscaped(b []byte, limit uint32) uint32 {
|
||||
bLen := len(b)
|
||||
cnt := 0
|
||||
pos := 0
|
||||
for cnt + pos < int(limit) && pos < bLen {
|
||||
if b[pos] == '/' || b[pos] =='\\' {
|
||||
cnt += 1
|
||||
}
|
||||
pos += 1
|
||||
|
||||
}
|
||||
return uint32(pos)
|
||||
}
|
||||
|
||||
func escape(s []byte) []byte {
|
||||
s = bytes.Replace(s, b("\\"), b("\\\\"), -1)
|
||||
return bytes.Replace(s, b("/"), b("\\/"), -1)
|
||||
}
|
||||
|
||||
func unescape(s []byte) []byte {
|
||||
s = bytes.Replace(s, b("\\/"), b("/"), -1)
|
||||
return bytes.Replace(s, b("\\\\"), b("\\"), -1)
|
||||
}
|
||||
|
||||
func checkscape(s []byte) bool {
|
||||
i := 0
|
||||
for i < len(s) - 1 {
|
||||
if s[i] == '/' {
|
||||
return false
|
||||
}
|
||||
if s[i] == '\\' {
|
||||
i += 1
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type ReverseServer struct {
|
||||
port uint16
|
||||
|
||||
}
|
||||
|
||||
func NewReverseServer(port uint16) *ReverseServer {
|
||||
return &ReverseServer{
|
||||
port,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ReverseServer) Run() {
|
||||
sock := NewLrcpServer(s.port)
|
||||
for {
|
||||
ses := sock.Accept()
|
||||
go s.handleSession(ses)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ReverseServer) handleSession(ses *LrcpSession) {
|
||||
r := bufio.NewReader(ses)
|
||||
for {
|
||||
data, err := r.ReadBytes('\n')
|
||||
if err != nil { return }
|
||||
data = reverse(data[:len(data)-1])
|
||||
ses.Write(append(data, '\n'))
|
||||
}
|
||||
}
|
||||
|
||||
type ReceivedData struct {
|
||||
data []byte
|
||||
pos uint32
|
||||
}
|
||||
|
||||
type LrcpSession struct {
|
||||
sessionId uint32
|
||||
ack uint32
|
||||
seq uint32
|
||||
acked uint32
|
||||
readPtr uint32
|
||||
readBuf uint32
|
||||
pc net.PacketConn
|
||||
addr net.Addr
|
||||
recv map[uint32]*ReceivedData
|
||||
dataQ chan uint32
|
||||
ackQ chan uint32
|
||||
closed bool
|
||||
last int64
|
||||
}
|
||||
|
||||
func NewLrcpSession(sessionId uint32, pc net.PacketConn, addr net.Addr) *LrcpSession {
|
||||
return &LrcpSession{
|
||||
sessionId,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
pc,
|
||||
addr,
|
||||
make(map[uint32]*ReceivedData),
|
||||
make(chan uint32, 100),
|
||||
make(chan uint32, 100),
|
||||
false,
|
||||
0,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LrcpSession) snd(buf []byte) error {
|
||||
var err error
|
||||
fmt.Printf("> %s\n", bytes.Replace(buf, b("\n"), b("\\n"), -1))
|
||||
_, err = s.pc.WriteTo(buf, s.addr)
|
||||
return err
|
||||
|
||||
}
|
||||
func (s *LrcpSession) Read(buf []byte) (int, error) {
|
||||
//fmt.Printf("reading len %d\n", len(buf))
|
||||
for s.readPtr >= s.ack {
|
||||
fmt.Printf("ack %d\n", s.ack)
|
||||
select {
|
||||
case <-s.dataQ:
|
||||
case <-time.After(60 * time.Second):
|
||||
s.sendClose()
|
||||
return 0, fmt.Errorf("timeout")
|
||||
}
|
||||
}
|
||||
//fmt.Println("read has data")
|
||||
r, ok := s.recv[s.readBuf]
|
||||
if ! ok {
|
||||
return 0, fmt.Errorf("recv buf %d not found", s.readBuf)
|
||||
}
|
||||
b := r.data
|
||||
posInBuf := s.readPtr - s.readBuf
|
||||
bytesLeft := uint32(len(b)) - posInBuf
|
||||
l := Min(uint32(len(buf)), bytesLeft)
|
||||
//fmt.Printf("Read returning %d bytes\n", l)
|
||||
copy(buf, b[posInBuf:posInBuf+l])
|
||||
bytesLeft -= l
|
||||
s.readPtr += l
|
||||
if bytesLeft == 0 {
|
||||
s.readBuf += uint32(len(b))
|
||||
}
|
||||
return int(l), nil
|
||||
}
|
||||
|
||||
func (s *LrcpSession) waitAck() bool {
|
||||
acked := false
|
||||
|
||||
for ! acked {
|
||||
select {
|
||||
case <- s.ackQ: acked = s.seq <= s.acked
|
||||
case <-time.After(3 * time.Second): return false
|
||||
}
|
||||
}
|
||||
|
||||
return acked
|
||||
}
|
||||
|
||||
func (s *LrcpSession) WriteString(b string) (int, error) {
|
||||
return s.Write([]byte(b))
|
||||
}
|
||||
|
||||
func (s *LrcpSession) Write(b []byte) (int, error) {
|
||||
bytesLeft := uint32(len(b))
|
||||
pos := uint32(0)
|
||||
for bytesLeft > 0 {
|
||||
// max packed len is 1k
|
||||
// 5 slashes + "data" + 2 decimal ints =~ 23, call it 30
|
||||
if s.closed {
|
||||
return int(pos), fmt.Errorf("closed")
|
||||
}
|
||||
l := calcMaxEscaped(b[pos:pos+bytesLeft], MAXPACKET-30)
|
||||
err := s.writeBlock(b[pos:pos+l])
|
||||
if err != nil { return int(pos), err}
|
||||
pos += l
|
||||
bytesLeft -= l
|
||||
}
|
||||
return int(pos), nil
|
||||
}
|
||||
|
||||
func (s *LrcpSession) writeBlock(b []byte) error {
|
||||
bLen := uint32(len(b))
|
||||
b = escape(b)
|
||||
hdr := fmt.Sprintf("/data/%d/%d/", s.sessionId, s.seq)
|
||||
|
||||
packet := append([]byte(hdr), b...)
|
||||
packet = append(packet, '/')
|
||||
s.seq += bLen
|
||||
acked := false
|
||||
var err error
|
||||
retries := 30
|
||||
for ! acked && retries > 0{
|
||||
if s.closed {
|
||||
return fmt.Errorf("closed")
|
||||
}
|
||||
//fmt.Printf("waiting for seq %d acked %d\n", s.seq, s.acked)
|
||||
err = s.snd(packet)
|
||||
if err != nil { return err }
|
||||
acked = s.waitAck()
|
||||
retries -= 1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *LrcpSession) sendAck() {
|
||||
m := fmt.Sprintf("/ack/%d/%d/", s.sessionId, s.ack)
|
||||
s.snd([]byte(m))
|
||||
}
|
||||
|
||||
func (s *LrcpSession) receiveData( pos uint32, data []byte ){
|
||||
// todo if pos in recv but len bigger, make a separate entry with higher pos and smalle data
|
||||
//fmt.Printf("receiving %d at %d\n", len(data), pos)
|
||||
//fmt.Printf("%+v\n", s.recv)
|
||||
d, ok := s.recv[pos]
|
||||
for ok {
|
||||
dlen := len(d.data)
|
||||
if dlen >= len(data) {
|
||||
//fmt.Printf("found %d bytes at %d which is more than %d so bailing out\n", dlen, pos, len(data))
|
||||
s.sendAck()
|
||||
return
|
||||
}
|
||||
pos += uint32(dlen)
|
||||
data = data[dlen:]
|
||||
//fmt.Printf("found %d bytes at pos, remaining %d at %d\n", dlen, len(data), pos)
|
||||
d, ok = s.recv[pos]
|
||||
}
|
||||
r := &ReceivedData{data, pos}
|
||||
s.recv[pos] = r
|
||||
s.processNewData()
|
||||
}
|
||||
|
||||
func (s *LrcpSession) processNewData() {
|
||||
r, ok := s.recv[s.ack]
|
||||
newData := ok
|
||||
|
||||
for ok {
|
||||
s.ack = r.pos + uint32(len(r.data))
|
||||
r, ok = s.recv[s.ack]
|
||||
}
|
||||
s.sendAck()
|
||||
if newData {
|
||||
s.dataQ <- s.ack
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LrcpSession) close() {
|
||||
s.closed = true
|
||||
}
|
||||
|
||||
func (s *LrcpSession) sendClose() {
|
||||
m := fmt.Sprintf("/close/%d/", s.sessionId)
|
||||
s.snd([]byte(m))
|
||||
}
|
||||
|
||||
|
||||
type LrcpServer struct {
|
||||
port uint16
|
||||
pc net.PacketConn
|
||||
sessions map[uint32]*LrcpSession
|
||||
acceptQ chan *LrcpSession
|
||||
}
|
||||
|
||||
func NewLrcpServer(port uint16) *LrcpServer {
|
||||
s := &LrcpServer{
|
||||
port,
|
||||
nil,
|
||||
make(map[uint32]*LrcpSession),
|
||||
make(chan *LrcpSession, 100),
|
||||
}
|
||||
go s.run()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *LrcpServer) run() {
|
||||
addr := fmt.Sprintf("0.0.0.0:%d", s.port)
|
||||
var err error
|
||||
s.pc, err = net.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer s.pc.Close()
|
||||
buf := make([]byte, 1000)
|
||||
fmt.Println("Reverse server listening for packets")
|
||||
for {
|
||||
n, addr, err := s.pc.ReadFrom(buf)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s.handle(addr, buf[:n])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LrcpServer) Accept() *LrcpSession {
|
||||
ses := <- s.acceptQ
|
||||
//fmt.Printf("Started session %d\n", ses.sessionId)
|
||||
ses.sendAck()
|
||||
return ses
|
||||
}
|
||||
|
||||
func (s *LrcpServer) handle(addr net.Addr, req []byte) {
|
||||
fmt.Printf("< %s\n", bytes.Replace(req, b("\n"), []byte("\\n"), -1))
|
||||
if ! bytes.HasPrefix(req, b("/")) || ! bytes.HasSuffix(req, b("/")) {
|
||||
return
|
||||
}
|
||||
_, req = splitSlash(req)
|
||||
cmd, args := splitSlash(req)
|
||||
var err error
|
||||
strSessionId, args := splitSlash(args)
|
||||
sessionId, err := b2i(strSessionId)
|
||||
if err != nil { return }
|
||||
switch string(cmd) {
|
||||
case "connect": err = s.hdlConnect(sessionId, addr)
|
||||
case "data": err = s.hdlData(sessionId, args, addr)
|
||||
case "ack": err = s.hdlAck(sessionId, args)
|
||||
case "close": err = s.hdlClose(sessionId)
|
||||
default: err = fmt.Errorf("unimplemented command %s\n", cmd)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LrcpServer) hdlConnect(sessionId uint32, addr net.Addr) error {
|
||||
|
||||
ses, ok := s.sessions[sessionId]
|
||||
if ok && ! ses.closed {
|
||||
ses.sendAck()
|
||||
return nil
|
||||
}
|
||||
ses = NewLrcpSession(sessionId, s.pc, addr)
|
||||
ses.last = time.Now().Unix()
|
||||
s.sessions[sessionId] = ses
|
||||
s.acceptQ <- ses
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (s *LrcpServer) hdlData(sessionId uint32, req []byte, addr net.Addr) error {
|
||||
ses, ok := s.sessions[sessionId]
|
||||
if !ok {
|
||||
s.sendClose(sessionId, addr)
|
||||
return fmt.Errorf("unknown session %d", sessionId)}
|
||||
ses.last = time.Now().Unix()
|
||||
strPos, req := splitSlash(req)
|
||||
pos, err:= b2i(strPos)
|
||||
if err != nil { return err }
|
||||
|
||||
data := req[:len(req)-1]
|
||||
if !checkscape(data) {
|
||||
return fmt.Errorf("invalid data")
|
||||
}
|
||||
data = unescape(data)
|
||||
//fmt.Printf("Data len %d for session %d pos %d\n", len(data), sessionId, pos)
|
||||
if len(data) == 0 {
|
||||
ses.sendAck()
|
||||
} else {
|
||||
ses.receiveData(pos, data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LrcpServer) hdlAck(sessionId uint32, req []byte) error {
|
||||
ses, ok := s.sessions[sessionId]
|
||||
if !ok { return fmt.Errorf("unknown session %d", sessionId)}
|
||||
strPos, req := splitSlash(req)
|
||||
pos, err:= b2i(strPos)
|
||||
if err != nil { return err }
|
||||
ses.acked = Max(ses.acked, pos)
|
||||
ses.ackQ <- pos
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LrcpServer) hdlClose(sessionId uint32) error {
|
||||
ses, ok := s.sessions[sessionId]
|
||||
if !ok { return fmt.Errorf("unknown session %d", sessionId)}
|
||||
s.sendClose(ses.sessionId, ses.addr)
|
||||
ses.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LrcpServer) sendClose(sessionId uint32, addr net.Addr) {
|
||||
m := fmt.Sprintf("/close/%d/", sessionId)
|
||||
fmt.Printf("> %s\n", m)
|
||||
|
||||
s.pc.WriteTo([]byte(m), addr)
|
||||
}
|
69
tests/reverse.py
Normal file
69
tests/reverse.py
Normal file
@ -0,0 +1,69 @@
|
||||
import socket
|
||||
from time import time
|
||||
|
||||
addr = ("localhost", 13370)
|
||||
ses = int(time())
|
||||
def sock():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
return s
|
||||
|
||||
def connect(s):
|
||||
s.sendto(f"/connect/{ses}/".encode(), addr)
|
||||
|
||||
def data(s):
|
||||
s.sendto(f"/data/{ses}/0/12/".encode(), addr)
|
||||
def data2(s):
|
||||
s.sendto(f"/data/{ses}/2/Hello world this is a long long test!\n/".encode(), addr)
|
||||
|
||||
def escdata(s):
|
||||
s.sendto(f"/data/{ses}/0/foo\/bar\/baz\nfoo\\bar\\baz\n/".encode(), addr)
|
||||
|
||||
def chunk1(s):
|
||||
s.sendto(f"/data/{ses}/0/snack/".encode(), addr)
|
||||
|
||||
def chunk2(s):
|
||||
s.sendto(f"/data/{ses}/0/snack snoep\nsnap/".encode(), addr)
|
||||
|
||||
def chunk3(s):
|
||||
s.sendto(f"/data/{ses}/0/snack snoep\nsnap snep\nslap\n/".encode(), addr)
|
||||
|
||||
def simple(s):
|
||||
connect(s)
|
||||
print(s.recv(1024).decode())
|
||||
data2(s)
|
||||
print(s.recv(1024).decode())
|
||||
data2(s)
|
||||
print(s.recv(1024).decode())
|
||||
data(s)
|
||||
print(s.recv(1024).decode())
|
||||
print(s.recv(1024).decode())
|
||||
print(s.recv(1024).decode())
|
||||
|
||||
def escaper(s):
|
||||
connect(s)
|
||||
print(s.recv(1024).decode())
|
||||
escdata(s)
|
||||
|
||||
print(s.recv(1024).decode())
|
||||
|
||||
def waiter(s):
|
||||
connect(s)
|
||||
print(s.recv(1024).decode())
|
||||
|
||||
|
||||
def chunker(s):
|
||||
connect(s)
|
||||
print(s.recv(1024).decode())
|
||||
chunk1(s)
|
||||
print(s.recv(1024).decode())
|
||||
chunk2(s)
|
||||
print(s.recv(1024).decode())
|
||||
chunk3(s)
|
||||
print(s.recv(1024).decode())
|
||||
print(s.recv(1024).decode())
|
||||
|
||||
|
||||
#simple(sock())
|
||||
#escaper(sock())
|
||||
#waiter(sock())
|
||||
chunker(sock())
|
Loading…
Reference in New Issue
Block a user