7 Commits
master ... ramp

Author SHA1 Message Date
idk
6026a5bc5f tolerate FROM_PORT and TO_PORT on datagrams 2019-04-29 17:04:13 -04:00
idk
15b139ea53 go fmt 2019-04-29 16:17:24 -04:00
idk
cbcc989bf6 use more retainable configs 2019-04-29 16:16:24 -04:00
idk
9e6b5e1031 further use of ramp 2019-04-29 11:47:38 -04:00
idk
cfcbc666ad try and reduce some complexity with ramp 2019-04-29 11:10:25 -04:00
idk
d4bff7e8c4 forgot to add moved i2pkeys dir 2019-04-20 14:53:50 -04:00
idk
f34c6f2619 export Conn and Resolver 2019-04-11 18:40:05 -04:00
7 changed files with 237 additions and 49 deletions

View File

@ -34,7 +34,7 @@ func (s *SAM) NewDatagramSession(id string, keys I2PKeys, options []string, udpP
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := net.SplitHostPort(s.Conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -47,7 +47,7 @@ func (s *SAM) NewDatagramSession(id string, keys I2PKeys, options []string, udpP
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := net.SplitHostPort(s.Conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err
@ -87,13 +87,13 @@ func (s *DatagramSession) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
}
break
}
i := bytes.IndexByte(buf, byte('\n'))
i := bytes.IndexByte(buf, byte(' '))
if i > 4096 || i > n {
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address.")
}
raddr, err := NewI2PAddrFromString(string(buf[:i]))
if err != nil {
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address: " + string(buf[:i]) + err.Error())
}
// shift out the incomming address to contain only the data received
if (n - i + 1) > len(b) {

View File

@ -27,7 +27,7 @@ func Test_DatagramServerClient(t *testing.T) {
}
// fmt.Println("\tServer: My address: " + keys.Addr().Base32())
fmt.Println("\tServer: Creating tunnel")
ds, err := sam.NewDatagramSession("DGserverTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
ds, err := sam.NewDatagramSession("DGserverTun", keys, []string{"inbound.length=1", "outbound.length=1", "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()
@ -47,14 +47,14 @@ func Test_DatagramServerClient(t *testing.T) {
return
}
fmt.Println("\tClient: Creating tunnel")
ds2, err := sam2.NewDatagramSession("DGclientTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
ds2, err := sam2.NewDatagramSession("DGclientTun", keys, []string{"inbound.length=1", "outbound.length=1", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
if err != nil {
c <- false
return
}
defer ds2.Close()
// fmt.Println("\tClient: Servers address: " + ds.LocalAddr().Base32())
// fmt.Println("\tClient: Clients address: " + ds2.LocalAddr().Base32())
fmt.Println("\tClient: Servers address: " + ds.B32())
fmt.Println("\tClient: Clients address: " + ds2.B32())
fmt.Println("\tClient: Tries to send datagram to server")
for {
select {

188
i2pkeys/I2PAddr.go Normal file
View File

@ -0,0 +1,188 @@
package i2pkeys
import (
"bytes"
"crypto/sha256"
"encoding/base32"
"encoding/base64"
"errors"
"io"
"strings"
)
var (
i2pB64enc *base64.Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
)
// The public and private keys associated with an I2P destination. I2P hides the
// details of exactly what this is, so treat them as blobs, but generally: One
// pair of DSA keys, one pair of ElGamal keys, and sometimes (almost never) also
// a certificate. String() returns you the full content of I2PKeys and Addr()
// returns the public keys.
type I2PKeys struct {
addr I2PAddr // only the public key
both string // both public and private keys
}
// Creates I2PKeys from an I2PAddr and a public/private keypair string (as
// generated by String().)
func NewKeys(addr I2PAddr, both string) I2PKeys {
return I2PKeys{addr, both}
}
// load keys from non standard format
func LoadKeysIncompat(r io.Reader) (k I2PKeys, err error) {
var buff bytes.Buffer
_, err = io.Copy(&buff, r)
if err == nil {
parts := strings.Split(buff.String(), "\n")
k = I2PKeys{I2PAddr(parts[0]), parts[1]}
}
return
}
// store keys in non standard format
func StoreKeysIncompat(k I2PKeys, w io.Writer) (err error) {
_, err = io.WriteString(w, k.addr.Base64()+"\n"+k.both)
return
}
// Returns the public keys of the I2PKeys.
func (k I2PKeys) Addr() I2PAddr {
return k.addr
}
// Returns the keys (both public and private), in I2Ps base64 format. Use this
// when you create sessions.
func (k I2PKeys) String() string {
return k.both
}
// I2PAddr represents an I2P destination, almost equivalent to an IP address.
// This is the humongously huge base64 representation of such an address, which
// really is just a pair of public keys and also maybe a certificate. (I2P hides
// the details of exactly what it is. Read the I2P specifications for more info.)
type I2PAddr string
// an i2p destination hash, the .b32.i2p address if you will
type I2PDestHash [32]byte
// create a desthash from a string b32.i2p address
func DestHashFromString(str string) (dhash I2PDestHash, err error) {
if strings.HasSuffix(str, ".b32.i2p") && len(str) == 60 {
// valid
_, err = i2pB32enc.Decode(dhash[:], []byte(str[:52]+"===="))
} else {
// invalid
err = errors.New("invalid desthash format")
}
return
}
// get string representation of i2p dest hash
func (h I2PDestHash) String() string {
b32addr := make([]byte, 56)
i2pB32enc.Encode(b32addr, h[:])
return string(b32addr[:52]) + ".b32.i2p"
}
// Returns "I2P"
func (h *I2PDestHash) Network() string {
return "I2P"
}
// Returns the base64 representation of the I2PAddr
func (a I2PAddr) Base64() string {
return string(a)
}
// Returns the I2P destination (base64-encoded)
func (a I2PAddr) String() string {
return string(a)
}
// Returns "I2P"
func (a I2PAddr) Network() string {
return "I2P"
}
// Creates a new I2P address from a base64-encoded string. Checks if the address
// addr is in correct format. (If you know for sure it is, use I2PAddr(addr).)
func NewI2PAddrFromString(addr string) (I2PAddr, error) {
if strings.HasSuffix(addr, ".i2p") {
if strings.HasSuffix(addr, ".b32.i2p") {
return I2PAddr(""), errors.New("cannot convert .b32.i2p to full destination")
}
// strip off .i2p if it's there
addr = addr[:len(addr)-4]
}
addr = strings.Trim(addr, "\t\n\r\f ")
// very basic check
if len(addr) > 4096 || len(addr) < 516 {
return I2PAddr(""), errors.New("Not an I2P address")
}
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
if _, err := i2pB64enc.Decode(buf, []byte(addr)); err != nil {
return I2PAddr(""), errors.New("Address is not base64-encoded")
}
return I2PAddr(addr), nil
}
func FiveHundredAs() I2PAddr {
s := ""
for x := 0; x < 517; x++ {
s += "A"
}
r, _ := NewI2PAddrFromString(s)
return r
}
// Creates a new I2P address from a byte array. The inverse of ToBytes().
func NewI2PAddrFromBytes(addr []byte) (I2PAddr, error) {
if len(addr) > 4096 || len(addr) < 384 {
return I2PAddr(""), errors.New("Not an I2P address")
}
buf := make([]byte, i2pB64enc.EncodedLen(len(addr)))
i2pB64enc.Encode(buf, addr)
return I2PAddr(string(buf)), nil
}
// Turns an I2P address to a byte array. The inverse of NewI2PAddrFromBytes().
func (addr I2PAddr) ToBytes() ([]byte, error) {
buf := make([]byte, i2pB64enc.DecodedLen(len(addr)))
if _, err := i2pB64enc.Decode(buf, []byte(addr)); err != nil {
return buf, errors.New("Address is not base64-encoded")
}
return buf, nil
}
func (addr I2PAddr) Bytes() []byte {
b, _ := addr.ToBytes()
return b
}
// Returns the *.b32.i2p address of the I2P address. It is supposed to be a
// somewhat human-manageable 64 character long pseudo-domain name equivalent of
// the 516+ characters long default base64-address (the I2PAddr format). It is
// not possible to turn the base32-address back into a usable I2PAddr without
// performing a Lookup(). Lookup only works if you are using the I2PAddr from
// which the b32 address was generated.
func (addr I2PAddr) Base32() (str string) {
return addr.DestHash().String()
}
func (addr I2PAddr) DestHash() (h I2PDestHash) {
hash := sha256.New()
b, _ := addr.ToBytes()
hash.Write(b)
digest := hash.Sum(nil)
copy(h[:], digest)
return
}
// Makes any string into a *.b32.i2p human-readable I2P address. This makes no
// sense, unless "anything" is an I2P destination of some sort.
func Base32(anything string) string {
return I2PAddr(anything).Base32()
}

4
raw.go
View File

@ -36,7 +36,7 @@ func (s *SAM) NewRawSession(id string, keys I2PKeys, options []string, udpPort i
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := net.SplitHostPort(s.Conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -49,7 +49,7 @@ func (s *SAM) NewRawSession(id string, keys I2PKeys, options []string, udpPort i
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := net.SplitHostPort(s.Conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err

View File

@ -34,12 +34,12 @@ func NewFullSAMResolver(address string) (*SAMResolver, error) {
// Performs a lookup, probably this order: 1) routers known addresses, cached
// addresses, 3) by asking peers in the I2P network.
func (sam *SAMResolver) Resolve(name string) (I2PAddr, error) {
if _, err := sam.conn.Write([]byte("NAMING LOOKUP NAME=" + name + "\n")); err != nil {
if _, err := sam.Conn.Write([]byte("NAMING LOOKUP NAME=" + name + "\n")); err != nil {
sam.Close()
return I2PAddr(""), err
}
buf := make([]byte, 4096)
n, err := sam.conn.Read(buf)
n, err := sam.Conn.Read(buf)
if err != nil {
sam.Close()
return I2PAddr(""), err

57
sam3.go
View File

@ -12,6 +12,7 @@ import (
)
import (
"github.com/eyedeekay/ramp/config"
. "github.com/eyedeekay/ramp/emit"
. "github.com/eyedeekay/sam3/i2pkeys"
)
@ -19,8 +20,8 @@ import (
// Used for controlling I2Ps SAMv3.
type SAM struct {
//address string
conn net.Conn
resolver *SAMResolver
Conn net.Conn
Resolver *SAMResolver
Config SAMEmit
}
@ -45,11 +46,13 @@ const (
func NewSAM(address string) (*SAM, error) {
var s SAM
// TODO: clean this up
conn, err := net.Dial("tcp", address)
s.Config.I2PConfig.SetSAMAddress(address)
s.Config.SamMax = "3.2"
conn, err := net.Dial("tcp", s.Config.I2PConfig.Sam())
if err != nil {
return nil, err
}
if _, err := conn.Write(s.Config.HelloBytes()); err != nil {
if _, err := conn.Write(s.Config.HelloBytes()); err != nil {
conn.Close()
return nil, err
}
@ -60,10 +63,9 @@ func NewSAM(address string) (*SAM, error) {
return nil, err
}
if strings.Contains(string(buf[:n]), "HELLO REPLY RESULT=OK") {
s.Config.I2PConfig.SetSAMAddress(address)
s.conn = conn
s.Config.I2PConfig.DestinationKeys = nil
s.resolver, err = NewSAMResolver(&s)
s.Conn = conn
//s.Config.I2PConfig.DestinationKeys = nil
s.Resolver, err = NewSAMResolver(&s)
if err != nil {
return nil, err
}
@ -80,7 +82,7 @@ func NewSAM(address string) (*SAM, error) {
func (sam *SAM) Keys() (k *I2PKeys) {
//TODO: copy them?
k = sam.Config.I2PConfig.DestinationKeys
k = &sam.Config.I2PConfig.DestinationKeys
return
}
@ -89,7 +91,7 @@ func (sam *SAM) ReadKeys(r io.Reader) (err error) {
var keys I2PKeys
keys, err = LoadKeysIncompat(r)
if err == nil {
sam.Config.I2PConfig.DestinationKeys = &keys
sam.Config.I2PConfig.DestinationKeys = keys
}
return
}
@ -100,7 +102,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
// transient
keys, err = sam.NewKeys()
if err == nil {
sam.Config.I2PConfig.DestinationKeys = &keys
sam.Config.I2PConfig.DestinationKeys = keys
}
} else {
// persistant
@ -109,7 +111,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
// make the keys
keys, err = sam.NewKeys()
if err == nil {
sam.Config.I2PConfig.DestinationKeys = &keys
sam.Config.I2PConfig.DestinationKeys = keys
// save keys
var f io.WriteCloser
f, err = os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, 0600)
@ -125,7 +127,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
if err == nil {
keys, err = LoadKeysIncompat(f)
if err == nil {
sam.Config.I2PConfig.DestinationKeys = &keys
sam.Config.I2PConfig.DestinationKeys = keys
}
}
}
@ -141,11 +143,11 @@ func (sam *SAM) NewKeys(sigType ...string) (I2PKeys, error) {
if len(sigType) > 0 {
sigtmp = sigType[0]
}
if _, err := sam.conn.Write([]byte("DEST GENERATE " + sigtmp + "\n")); err != nil {
if _, err := sam.Conn.Write([]byte("DEST GENERATE " + sigtmp + "\n")); err != nil {
return I2PKeys{}, err
}
buf := make([]byte, 8192)
n, err := sam.conn.Read(buf)
n, err := sam.Conn.Read(buf)
if err != nil {
return I2PKeys{}, err
}
@ -173,7 +175,7 @@ func (sam *SAM) NewKeys(sigType ...string) (I2PKeys, error) {
// Performs a lookup, probably this order: 1) routers known addresses, cached
// addresses, 3) by asking peers in the I2P network.
func (sam *SAM) Lookup(name string) (I2PAddr, error) {
return sam.resolver.Resolve(name)
return sam.Resolver.Resolve(name)
}
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
@ -185,24 +187,21 @@ func (sam *SAM) newGenericSession(style, id string, keys I2PKeys, options []stri
return sam.newGenericSessionWithSignature(style, id, keys, Sig_NONE, options, extras)
}
func (sam *SAM) newGenericSessionWithSignature(style, id string, keys I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
return sam.newGenericSessionWithSignatureAndPorts(style, id, "0", "0", keys, sigType, options, extras)
}
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
// for a new I2P tunnel with name id, using the cypher keys specified, with the
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
// setting extra to something else than []string{}.
// This sam3 instance is now a session
func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to string, keys I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
func (sam *SAM) newGenericSessionWithSignature(style, id string, keys I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
conf, _ := i2pconfig.ConstructEqualsConfig(append(options))
sam.Config.I2PConfig = *conf
sam.Config.SigType = sigType
sam.Config.Style = style
sam.Config.DestinationKeys = keys
sam.Config.TunName = id
optStr := ""
for _, opt := range options {
optStr += opt + " "
}
conn := sam.conn
scmsg := []byte("SESSION CREATE STYLE=" + style + " FROM_PORT=" + from + " TO_PORT=" + to + " ID=" + id + " DESTINATION=" + keys.String() + " " + sigType + " " + optStr + strings.Join(extras, " ") + "\n")
conn := sam.Conn
scmsg := []byte("SESSION CREATE " + sam.Config.SessionStyle() + sam.Config.ID() + sam.Config.DestinationKey() + sam.Config.SignatureType() + sam.Config.FromPort() + sam.Config.ToPort() + sam.Config.OptStr() + strings.Join(extras, " ") + "\n")
for m, i := 0, 0; m != len(scmsg); i++ {
if i == 15 {
conn.Close()
@ -248,5 +247,5 @@ func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to strin
// close this sam session
func (sam *SAM) Close() error {
return sam.conn.Close()
return sam.Conn.Close()
}

View File

@ -83,12 +83,12 @@ func (sam *SAM) NewStreamSessionWithSignature(id string, keys I2PKeys, options [
// Creates a new StreamSession with the I2CP- and streaminglib options as
// specified. See the I2P documentation for a full list of options.
func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys I2PKeys, options []string, sigType string) (*StreamSession, error) {
conn, err := sam.newGenericSessionWithSignatureAndPorts("STREAM", id, from, to, keys, sigType, options, []string{})
func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id string, keys I2PKeys, options []string, sigType string) (*StreamSession, error) {
conn, err := sam.newGenericSessionWithSignature("STREAM", id, keys, sigType, options, []string{})
if err != nil {
return nil, err
}
return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, keys, time.Duration(600 * time.Second), time.Now(), sigType, from, to}, nil
return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, keys, time.Duration(600 * time.Second), time.Now(), sigType, sam.Config.Fromport, sam.Config.Toport}, nil
}
// lookup name, convienence function
@ -188,8 +188,9 @@ func (s *StreamSession) DialI2P(addr I2PAddr) (*SAMConn, error) {
if err != nil {
return nil, err
}
conn := sam.conn
_, err = conn.Write([]byte("STREAM CONNECT ID=" + s.id + " FROM_PORT=" + s.from + " TO_PORT=" + s.to + " DESTINATION=" + addr.Base64() + " SILENT=false\n"))
conn := sam.Conn
// + sam.Config.ID()
_, err = conn.Write([]byte("STREAM CONNECT ID=" + s.id + sam.Config.FromPort() + sam.Config.ToPort() + " DESTINATION=" + addr.Base64() + " SILENT=false\n"))
if err != nil {
conn.Close()
return nil, err
@ -306,9 +307,9 @@ func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
if err == nil {
// we connected to sam
// send accept() command
_, err = io.WriteString(s.conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n")
_, err = io.WriteString(s.Conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n")
// read reply
rd := bufio.NewReader(s.conn)
rd := bufio.NewReader(s.Conn)
// read first line
line, err := rd.ReadString(10)
log.Println(line)
@ -326,7 +327,7 @@ func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
return &SAMConn{
laddr: l.laddr,
raddr: I2PAddr(dest),
conn: s.conn,
conn: s.Conn,
}, nil
} else {
s.Close()