RAW sessions works :]
This commit is contained in:
54
README.md
54
README.md
@ -9,7 +9,7 @@ This library is much better than ccondom (that use BOB), much more stable and mu
|
||||
**What works:**
|
||||
|
||||
* Utils
|
||||
* Resolving URLs to I2P destinations
|
||||
* Resolving domain names to I2P destinations
|
||||
* .b32.i2p hashes
|
||||
* Generating keys/i2p destinations
|
||||
* Streaming
|
||||
@ -18,20 +18,66 @@ This library is much better than ccondom (that use BOB), much more stable and mu
|
||||
* Implements net.Conn and net.Listener
|
||||
* Datagrams
|
||||
* Implements net.PacketConn
|
||||
* Raw datagrams
|
||||
* Like datagrams, but without addresses
|
||||
|
||||
**Does not work:**
|
||||
|
||||
* Raw packets
|
||||
* Everything works! :D
|
||||
* Probably needs some real-world testing
|
||||
|
||||
## Documentation ##
|
||||
|
||||
* Enter `godoc -http=:8081` into your terminal and hit enter.
|
||||
* Goto http://localhost:8081, click packages, and navigate to sam3
|
||||
|
||||
## Examples ##
|
||||
´´´go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bitbucket.org/kallevedin/sam3"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const yoursam = "127.0.0.1:7656" // sam bridge
|
||||
|
||||
func client(server I2PAddr) {
|
||||
sam, _ := NewSAM(yoursam)
|
||||
keys, _ := sam.NewKeys()
|
||||
stream, _ := sam2.NewStreamSession("clientTun", keys, Options_Small)
|
||||
fmt.Println("Client: Connecting to " + server.Base32())
|
||||
conn, _ := stream.DialI2P(server)
|
||||
conn.Write([]byte("Hello world!"))
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
sam, _ := NewSAM(yoursam)
|
||||
keys, _ := sam.NewKeys()
|
||||
go client(keys.Addr())
|
||||
stream, _ := sam.NewStreamSession("serverTun", keys, Options_Medium)
|
||||
listener, _ := stream.Listen()
|
||||
conn, _ := listener.Accept()
|
||||
buf := make([]byte, 4096)
|
||||
n,_ := conn.Read(buf)
|
||||
fmt.Println("Server received: " + string(buf[:n]))
|
||||
}
|
||||
´´´
|
||||
|
||||
The above will write to the terminal:
|
||||
|
||||
```text
|
||||
Client: Connecting to zjnvfh4hs3et5vtz35ogwzrws26zvwkcad5uo5esecvg4qpk5b4a.b32.i2p
|
||||
Server received: Hello world!
|
||||
```
|
||||
|
||||
Error handling was omitted in the above code for readability.
|
||||
|
||||
## Testing ##
|
||||
|
||||
* `go test` runs the whole suite
|
||||
* `go test -short` runs the shorter variant
|
||||
* `go test` runs the whole suite (takes 90+ sec to perform!)
|
||||
* `go test -short` runs the shorter variant, does not connect to anything
|
||||
|
||||
## License ##
|
||||
|
||||
|
25
datagram.go
25
datagram.go
@ -16,9 +16,9 @@ type DatagramSession struct {
|
||||
samAddr string // address to the sam bridge (ipv4:port)
|
||||
id string // tunnel name
|
||||
conn net.Conn // connection to sam bridge
|
||||
udpconn *net.UDPConn // used to deliver datagrams
|
||||
udpconn *net.UDPConn // used to deliver datagrams
|
||||
keys I2PKeys // i2p destination keys
|
||||
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
}
|
||||
|
||||
// Creates a new datagram session. udpPort is the UDP port SAM is listening on,
|
||||
@ -66,9 +66,17 @@ func (s *DatagramSession) ReadFrom(b []byte) (n int, addr I2PAddr, err error) {
|
||||
// extra bytes to read the remote address of incomming datagram
|
||||
buf := make([]byte, len(b) + 4096)
|
||||
|
||||
n, _, err = s.udpconn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return 0, I2PAddr(""), err
|
||||
for {
|
||||
// very basic protection: only accept incomming UDP messages from the IP of the SAM bridge
|
||||
var saddr *net.UDPAddr
|
||||
n, saddr, err = s.udpconn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return 0, I2PAddr(""), err
|
||||
}
|
||||
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
i := bytes.IndexByte(buf, byte('\n'))
|
||||
if i > 4096 || i > n {
|
||||
@ -79,12 +87,13 @@ func (s *DatagramSession) ReadFrom(b []byte) (n int, addr I2PAddr, err error) {
|
||||
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
|
||||
}
|
||||
// shift out the incomming address to contain only the data received
|
||||
copy(b, buf[i+1:i+1+len(b)])
|
||||
|
||||
if ( n - i+1 ) > len(b) {
|
||||
copy(b, buf[i+1:i+1+len(b)])
|
||||
return n-(i+1), raddr, errors.New("Datagram did not fit into your buffer.")
|
||||
} else {
|
||||
copy(b, buf[i+1:n])
|
||||
return n-(i+1), raddr, nil
|
||||
}
|
||||
return n-(i+1), raddr, nil
|
||||
}
|
||||
|
||||
// Sends one signed datagram to the destination specified. At the time of
|
||||
|
120
raw.go
Normal file
120
raw.go
Normal file
@ -0,0 +1,120 @@
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The RawSession provides no authentication of senders, and there is no sender
|
||||
// address attached to datagrams, so all communication is anonymous. The
|
||||
// messages send are however still endpoint-to-endpoint encrypted. You
|
||||
// need to figure out a way to identify and authenticate clients yourself, iff
|
||||
// that is needed. Raw datagrams may be at most 32 kB in size. There is no
|
||||
// overhead of authentication, which is the reason to use this..
|
||||
type RawSession struct {
|
||||
samAddr string // address to the sam bridge (ipv4:port)
|
||||
id string // tunnel name
|
||||
conn net.Conn // connection to sam bridge
|
||||
udpconn *net.UDPConn // used to deliver datagrams
|
||||
keys I2PKeys // i2p destination keys
|
||||
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
}
|
||||
|
||||
// Creates a new raw session. udpPort is the UDP port SAM is listening on,
|
||||
// and if you set it to zero, it will use SAMs standard UDP port.
|
||||
func (s *SAM) NewRawSession(id string, keys I2PKeys, options []string, udpPort int) (*RawSession, error) {
|
||||
if udpPort > 65335 || udpPort < 0 {
|
||||
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
||||
}
|
||||
if udpPort == 0 {
|
||||
udpPort = 7655
|
||||
}
|
||||
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
|
||||
if err != nil {
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost + ":0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost + ":" + strconv.Itoa(udpPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
||||
conn, err := s.newGenericSession("RAW", id, keys, options, []string{"PORT=" + lport})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RawSession{s.address, id, conn, udpconn, keys, rUDPAddr}, nil
|
||||
}
|
||||
|
||||
// Reads one raw datagram sent to the destination of the DatagramSession. Returns
|
||||
// the number of bytes read. Who sent the raw message can not be determined at
|
||||
// this layer - you need to do it (in a secure way!).
|
||||
func (s *RawSession) Read(b []byte) (n int, err error) {
|
||||
for {
|
||||
// very basic protection: only accept incomming UDP messages from the IP of the SAM bridge
|
||||
var saddr *net.UDPAddr
|
||||
n, saddr, err = s.udpconn.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Sends one raw datagram to the destination specified. At the time of writing,
|
||||
// maximum size is 32 kilobyte, but this may change in the future.
|
||||
func (s *RawSession) WriteTo(b []byte, addr I2PAddr) (n int, err error) {
|
||||
header := []byte("3.0 " + s.id + " " + addr.String() + "\n")
|
||||
msg := append(header, b...)
|
||||
n, err = s.udpconn.WriteToUDP(msg, s.rUDPAddr)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Closes the RawSession.
|
||||
func (s *RawSession) Close() error {
|
||||
err := s.conn.Close()
|
||||
err2 := s.udpconn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
// Returns the local I2P destination of the RawSession.
|
||||
func (s *RawSession) LocalAddr() I2PAddr {
|
||||
return s.keys.Addr()
|
||||
}
|
||||
|
||||
func (s *RawSession) SetDeadline(t time.Time) error {
|
||||
return s.udpconn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (s *RawSession) SetReadDeadline(t time.Time) error {
|
||||
return s.udpconn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (s *RawSession) SetWriteDeadline(t time.Time) error {
|
||||
return s.udpconn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
|
90
sam_test.go
90
sam_test.go
@ -4,7 +4,6 @@ package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -159,9 +158,6 @@ func Test_StreamingServerClient(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
ncpu := runtime.NumCPU()
|
||||
runtime.GOMAXPROCS(ncpu + 1)
|
||||
|
||||
fmt.Println("Test_StreamingServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
@ -242,12 +238,9 @@ func Test_StreamingServerClient(t *testing.T) {
|
||||
|
||||
|
||||
func Test_DatagramServerClient(t *testing.T) {
|
||||
// if testing.Short() {
|
||||
// return
|
||||
// }
|
||||
|
||||
ncpu := runtime.NumCPU()
|
||||
runtime.GOMAXPROCS(ncpu + 1)
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_DatagramServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
@ -322,3 +315,80 @@ func Test_DatagramServerClient(t *testing.T) {
|
||||
// fmt.Println("\tServer: Senders address was: " + saddr.Base32())
|
||||
}
|
||||
|
||||
|
||||
|
||||
func Test_RawServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_RawServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
rs, err := sam.NewDatagramSession("RAWserverTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
fmt.Println("Server: Failed to create tunnel: " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan(bool)) {
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
rs2, err := sam2.NewDatagramSession("RAWclientTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer rs2.Close()
|
||||
fmt.Println("\tClient: Tries to send raw datagram to server")
|
||||
for {
|
||||
select {
|
||||
default :
|
||||
_, err = rs2.WriteTo([]byte("Hello raw-world! <3 <3 <3 <3 <3 <3"), rs.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Println("\tClient: Failed to send raw datagram: " + err.Error())
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
case <-w :
|
||||
fmt.Println("\tClient: Sent raw datagram, quitting.")
|
||||
return
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
buf := make([]byte, 512)
|
||||
fmt.Println("\tServer: Read() waiting...")
|
||||
n, _, err := rs.ReadFrom(buf)
|
||||
w <- true
|
||||
if err != nil {
|
||||
fmt.Println("\tServer: Failed to Read(): " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Received datagram: " + string(buf[:n]))
|
||||
// fmt.Println("\tServer: Senders address was: " + saddr.Base32())
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user