completely remove I2PAddr.go to its own thing so it can be used separately
This commit is contained in:
188
I2PAddr.go
188
I2PAddr.go
@ -1,188 +0,0 @@
|
||||
package sam3
|
||||
|
||||
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()
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Implements net.Conn
|
||||
type SAMConn struct {
|
||||
laddr I2PAddr
|
||||
raddr I2PAddr
|
||||
laddr i2pkeys.I2PAddr
|
||||
raddr i2pkeys.I2PAddr
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
@ -34,7 +35,7 @@ func (sc *SAMConn) LocalAddr() net.Addr {
|
||||
}
|
||||
|
||||
// Implements net.Conn
|
||||
func (sc *SAMConn) localAddr() I2PAddr {
|
||||
func (sc *SAMConn) localAddr() i2pkeys.I2PAddr {
|
||||
return sc.laddr
|
||||
}
|
||||
|
||||
@ -43,7 +44,7 @@ func (sc *SAMConn) RemoteAddr() net.Addr {
|
||||
}
|
||||
|
||||
// Implements net.Conn
|
||||
func (sc *SAMConn) remoteAddr() I2PAddr {
|
||||
func (sc *SAMConn) remoteAddr() i2pkeys.I2PAddr {
|
||||
return sc.raddr
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// sam config
|
||||
@ -34,7 +36,7 @@ func (cfg *Config) StreamSession() (session *StreamSession, err error) {
|
||||
s, err = NewSAM(cfg.Addr)
|
||||
if err == nil {
|
||||
// ensure keys exist
|
||||
var keys I2PKeys
|
||||
var keys i2pkeys.I2PKeys
|
||||
keys, err = s.EnsureKeyfile(cfg.Keyfile)
|
||||
if err == nil {
|
||||
// create session
|
||||
@ -51,7 +53,7 @@ func (cfg *Config) DatagramSession() (session *DatagramSession, err error) {
|
||||
s, err = NewSAM(cfg.Addr)
|
||||
if err == nil {
|
||||
// ensure keys exist
|
||||
var keys I2PKeys
|
||||
var keys i2pkeys.I2PKeys
|
||||
keys, err = s.EnsureKeyfile(cfg.Keyfile)
|
||||
if err == nil {
|
||||
// determine udp port
|
||||
|
26
datagram.go
26
datagram.go
@ -6,6 +6,8 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// The DatagramSession implements net.PacketConn. It works almost like ordinary
|
||||
@ -13,17 +15,17 @@ import (
|
||||
// also end-to-end encrypted, signed and includes replay-protection. And they
|
||||
// are also built to be surveillance-resistant (yey!).
|
||||
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
|
||||
keys I2PKeys // i2p destination keys
|
||||
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
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.I2PKeys // i2p destination keys
|
||||
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
}
|
||||
|
||||
// Creates a new datagram 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) NewDatagramSession(id string, keys I2PKeys, options []string, udpPort int) (*DatagramSession, error) {
|
||||
func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int) (*DatagramSession, error) {
|
||||
if udpPort > 65335 || udpPort < 0 {
|
||||
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
||||
}
|
||||
@ -76,7 +78,7 @@ func (s *DatagramSession) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
var saddr *net.UDPAddr
|
||||
n, saddr, err = s.udpconn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return 0, I2PAddr(""), err
|
||||
return 0, i2pkeys.I2PAddr(""), err
|
||||
}
|
||||
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
|
||||
continue
|
||||
@ -85,11 +87,11 @@ func (s *DatagramSession) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
}
|
||||
i := bytes.IndexByte(buf, byte('\n'))
|
||||
if i > 4096 || i > n {
|
||||
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address.")
|
||||
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address.")
|
||||
}
|
||||
raddr, err := NewI2PAddrFromString(string(buf[:i]))
|
||||
raddr, err := i2pkeys.NewI2PAddrFromString(string(buf[:i]))
|
||||
if err != nil {
|
||||
return 0, I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
|
||||
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
|
||||
}
|
||||
// shift out the incomming address to contain only the data received
|
||||
if (n - i + 1) > len(b) {
|
||||
@ -122,7 +124,7 @@ func (s *DatagramSession) Close() error {
|
||||
}
|
||||
|
||||
// Returns the I2P destination of the DatagramSession.
|
||||
func (s *DatagramSession) LocalI2PAddr() I2PAddr {
|
||||
func (s *DatagramSession) LocalI2PAddr() i2pkeys.I2PAddr {
|
||||
return s.keys.Addr()
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,8 @@ var (
|
||||
// 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
|
||||
Address I2PAddr // only the public key
|
||||
Both string // both public and private keys
|
||||
}
|
||||
|
||||
// Creates I2PKeys from an I2PAddr and a public/private keypair string (as
|
||||
@ -44,19 +44,19 @@ func LoadKeysIncompat(r io.Reader) (k I2PKeys, err error) {
|
||||
|
||||
// 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)
|
||||
_, err = io.WriteString(w, k.Address.Base64()+"\n"+k.Both)
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the public keys of the I2PKeys.
|
||||
func (k I2PKeys) Addr() I2PAddr {
|
||||
return k.addr
|
||||
return k.Address
|
||||
}
|
||||
|
||||
// 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
|
||||
return k.Both
|
||||
}
|
||||
|
||||
// I2PAddr represents an I2P destination, almost equivalent to an IP address.
|
||||
|
20
raw.go
20
raw.go
@ -6,6 +6,8 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// The RawSession provides no authentication of senders, and there is no sender
|
||||
@ -15,17 +17,17 @@ import (
|
||||
// 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
|
||||
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.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) {
|
||||
func (s *SAM) NewRawSession(id string, keys i2pkeys.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")
|
||||
}
|
||||
@ -83,7 +85,7 @@ func (s *RawSession) Read(b []byte) (n int, err error) {
|
||||
|
||||
// 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) {
|
||||
func (s *RawSession) WriteTo(b []byte, addr i2pkeys.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)
|
||||
@ -101,7 +103,7 @@ func (s *RawSession) Close() error {
|
||||
}
|
||||
|
||||
// Returns the local I2P destination of the RawSession.
|
||||
func (s *RawSession) LocalAddr() I2PAddr {
|
||||
func (s *RawSession) LocalAddr() i2pkeys.I2PAddr {
|
||||
return s.keys.Addr()
|
||||
}
|
||||
|
||||
|
14
resolver.go
14
resolver.go
@ -5,6 +5,8 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
type SAMResolver struct {
|
||||
@ -29,19 +31,19 @@ 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) {
|
||||
func (sam *SAMResolver) Resolve(name string) (i2pkeys.I2PAddr, error) {
|
||||
if _, err := sam.conn.Write([]byte("NAMING LOOKUP NAME=" + name + "\n")); err != nil {
|
||||
sam.Close()
|
||||
return I2PAddr(""), err
|
||||
return i2pkeys.I2PAddr(""), err
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := sam.conn.Read(buf)
|
||||
if err != nil {
|
||||
sam.Close()
|
||||
return I2PAddr(""), err
|
||||
return i2pkeys.I2PAddr(""), err
|
||||
}
|
||||
if n <= 13 || !strings.HasPrefix(string(buf[:n]), "NAMING REPLY ") {
|
||||
return I2PAddr(""), errors.New("Failed to parse.")
|
||||
return i2pkeys.I2PAddr(""), errors.New("Failed to parse.")
|
||||
}
|
||||
s := bufio.NewScanner(bytes.NewReader(buf[13:n]))
|
||||
s.Split(bufio.ScanWords)
|
||||
@ -58,12 +60,12 @@ func (sam *SAMResolver) Resolve(name string) (I2PAddr, error) {
|
||||
} else if text == "NAME="+name {
|
||||
continue
|
||||
} else if strings.HasPrefix(text, "VALUE=") {
|
||||
return I2PAddr(text[6:]), nil
|
||||
return i2pkeys.I2PAddr(text[6:]), nil
|
||||
} else if strings.HasPrefix(text, "MESSAGE=") {
|
||||
errStr += " " + text[8:]
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return I2PAddr(""), errors.New(errStr)
|
||||
return i2pkeys.I2PAddr(""), errors.New(errStr)
|
||||
}
|
||||
|
34
sam3.go
34
sam3.go
@ -9,6 +9,8 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// Used for controlling I2Ps SAMv3.
|
||||
@ -16,7 +18,7 @@ type SAM struct {
|
||||
address string
|
||||
conn net.Conn
|
||||
resolver *SAMResolver
|
||||
keys *I2PKeys
|
||||
keys *i2pkeys.I2PKeys
|
||||
sigType int
|
||||
}
|
||||
|
||||
@ -74,7 +76,7 @@ func NewSAM(address string) (*SAM, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sam *SAM) Keys() (k *I2PKeys) {
|
||||
func (sam *SAM) Keys() (k *i2pkeys.I2PKeys) {
|
||||
//TODO: copy them?
|
||||
k = sam.keys
|
||||
return
|
||||
@ -82,8 +84,8 @@ func (sam *SAM) Keys() (k *I2PKeys) {
|
||||
|
||||
// read public/private keys from an io.Reader
|
||||
func (sam *SAM) ReadKeys(r io.Reader) (err error) {
|
||||
var keys I2PKeys
|
||||
keys, err = LoadKeysIncompat(r)
|
||||
var keys i2pkeys.I2PKeys
|
||||
keys, err = i2pkeys.LoadKeysIncompat(r)
|
||||
if err == nil {
|
||||
sam.keys = &keys
|
||||
}
|
||||
@ -91,7 +93,7 @@ func (sam *SAM) ReadKeys(r io.Reader) (err error) {
|
||||
}
|
||||
|
||||
// if keyfile fname does not exist
|
||||
func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
|
||||
func (sam *SAM) EnsureKeyfile(fname string) (keys i2pkeys.I2PKeys, err error) {
|
||||
if fname == "" {
|
||||
// transient
|
||||
keys, err = sam.NewKeys()
|
||||
@ -110,7 +112,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
|
||||
var f io.WriteCloser
|
||||
f, err = os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err == nil {
|
||||
err = StoreKeysIncompat(keys, f)
|
||||
err = i2pkeys.StoreKeysIncompat(keys, f)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
@ -119,7 +121,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
|
||||
var f *os.File
|
||||
f, err = os.Open(fname)
|
||||
if err == nil {
|
||||
keys, err = LoadKeysIncompat(f)
|
||||
keys, err = i2pkeys.LoadKeysIncompat(f)
|
||||
if err == nil {
|
||||
sam.keys = &keys
|
||||
}
|
||||
@ -132,18 +134,18 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys I2PKeys, err error) {
|
||||
// Creates the I2P-equivalent of an IP address, that is unique and only the one
|
||||
// who has the private keys can send messages from. The public keys are the I2P
|
||||
// desination (the address) that anyone can send messages to.
|
||||
func (sam *SAM) NewKeys(sigType ...string) (I2PKeys, error) {
|
||||
func (sam *SAM) NewKeys(sigType ...string) (i2pkeys.I2PKeys, error) {
|
||||
sigtmp := ""
|
||||
if len(sigType) > 0 {
|
||||
sigtmp = sigType[0]
|
||||
}
|
||||
if _, err := sam.conn.Write([]byte("DEST GENERATE " + sigtmp + "\n")); err != nil {
|
||||
return I2PKeys{}, err
|
||||
return i2pkeys.I2PKeys{}, err
|
||||
}
|
||||
buf := make([]byte, 8192)
|
||||
n, err := sam.conn.Read(buf)
|
||||
if err != nil {
|
||||
return I2PKeys{}, err
|
||||
return i2pkeys.I2PKeys{}, err
|
||||
}
|
||||
s := bufio.NewScanner(bytes.NewReader(buf[:n]))
|
||||
s.Split(bufio.ScanWords)
|
||||
@ -160,15 +162,15 @@ func (sam *SAM) NewKeys(sigType ...string) (I2PKeys, error) {
|
||||
} else if strings.HasPrefix(text, "PRIV=") {
|
||||
priv = text[5:]
|
||||
} else {
|
||||
return I2PKeys{}, errors.New("Failed to parse keys.")
|
||||
return i2pkeys.I2PKeys{}, errors.New("Failed to parse keys.")
|
||||
}
|
||||
}
|
||||
return I2PKeys{I2PAddr(pub), priv}, nil
|
||||
return i2pkeys.I2PKeys{i2pkeys.I2PAddr(pub), priv}, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func (sam *SAM) Lookup(name string) (i2pkeys.I2PAddr, error) {
|
||||
return sam.resolver.Resolve(name)
|
||||
}
|
||||
|
||||
@ -177,11 +179,11 @@ func (sam *SAM) Lookup(name string) (I2PAddr, error) {
|
||||
// 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) newGenericSession(style, id string, keys I2PKeys, options []string, extras []string) (net.Conn, error) {
|
||||
func (sam *SAM) newGenericSession(style, id string, keys i2pkeys.I2PKeys, options []string, extras []string) (net.Conn, error) {
|
||||
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) {
|
||||
func (sam *SAM) newGenericSessionWithSignature(style, id string, keys i2pkeys.I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
|
||||
return sam.newGenericSessionWithSignatureAndPorts(style, id, "0", "0", keys, sigType, options, extras)
|
||||
}
|
||||
|
||||
@ -190,7 +192,7 @@ func (sam *SAM) newGenericSessionWithSignature(style, id string, keys I2PKeys, s
|
||||
// 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) newGenericSessionWithSignatureAndPorts(style, id, from, to string, keys i2pkeys.I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
|
||||
|
||||
optStr := ""
|
||||
for _, opt := range options {
|
||||
|
@ -27,7 +27,7 @@ func Test_Basic(t *testing.T) {
|
||||
t.Fail()
|
||||
} else {
|
||||
fmt.Println("\tAddress created: " + keys.Addr().Base32())
|
||||
fmt.Println("\tI2PKeys: " + string(keys.both)[:50] + "(...etc)")
|
||||
fmt.Println("\tI2PKeys: " + string(keys.Both)[:50] + "(...etc)")
|
||||
}
|
||||
|
||||
addr2, err := sam.Lookup("zzz.i2p")
|
||||
|
38
stream.go
38
stream.go
@ -9,14 +9,16 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// Represents a streaming session.
|
||||
type StreamSession struct {
|
||||
samAddr string // address to the sam bridge (ipv4:port)
|
||||
id string // tunnel name
|
||||
conn net.Conn // connection to sam
|
||||
keys I2PKeys // i2p destination keys
|
||||
samAddr string // address to the sam bridge (ipv4:port)
|
||||
id string // tunnel name
|
||||
conn net.Conn // connection to sam
|
||||
keys i2pkeys.I2PKeys // i2p destination keys
|
||||
Timeout time.Duration
|
||||
Deadline time.Time
|
||||
sigType string
|
||||
@ -46,18 +48,18 @@ func (ss *StreamSession) Close() error {
|
||||
}
|
||||
|
||||
// Returns the I2P destination (the address) of the stream session
|
||||
func (ss *StreamSession) Addr() I2PAddr {
|
||||
func (ss *StreamSession) Addr() i2pkeys.I2PAddr {
|
||||
return ss.keys.Addr()
|
||||
}
|
||||
|
||||
// Returns the keys associated with the stream session
|
||||
func (ss *StreamSession) Keys() I2PKeys {
|
||||
func (ss *StreamSession) Keys() i2pkeys.I2PKeys {
|
||||
return ss.keys
|
||||
}
|
||||
|
||||
// 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) NewStreamSession(id string, keys I2PKeys, options []string) (*StreamSession, error) {
|
||||
func (sam *SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []string) (*StreamSession, error) {
|
||||
conn, err := sam.newGenericSession("STREAM", id, keys, options, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -67,7 +69,7 @@ func (sam *SAM) NewStreamSession(id string, keys I2PKeys, options []string) (*St
|
||||
|
||||
// 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) NewStreamSessionWithSignature(id string, keys I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
func (sam *SAM) NewStreamSessionWithSignature(id string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
conn, err := sam.newGenericSessionWithSignature("STREAM", id, keys, sigType, options, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -77,7 +79,7 @@ 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) {
|
||||
func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
conn, err := sam.newGenericSessionWithSignatureAndPorts("STREAM", id, from, to, keys, sigType, options, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -86,14 +88,14 @@ func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys
|
||||
}
|
||||
|
||||
// lookup name, convienence function
|
||||
func (s *StreamSession) Lookup(name string) (I2PAddr, error) {
|
||||
func (s *StreamSession) Lookup(name string) (i2pkeys.I2PAddr, error) {
|
||||
sam, err := NewSAM(s.samAddr)
|
||||
if err == nil {
|
||||
addr, err := sam.Lookup(name)
|
||||
sam.Close()
|
||||
return addr, err
|
||||
}
|
||||
return I2PAddr(""), err
|
||||
return i2pkeys.I2PAddr(""), err
|
||||
}
|
||||
|
||||
// context-aware dialer, eventually...
|
||||
@ -115,7 +117,7 @@ func (s *StreamSession) DialContextI2P(ctx context.Context, n, addr string) (*SA
|
||||
}
|
||||
}
|
||||
|
||||
i2paddr, err := NewI2PAddrFromString(addr)
|
||||
i2paddr, err := i2pkeys.NewI2PAddrFromString(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -157,7 +159,7 @@ func (s *StreamSession) deadline(ctx context.Context, now time.Time) (earliest t
|
||||
// implement net.Dialer
|
||||
func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
|
||||
|
||||
var i2paddr I2PAddr
|
||||
var i2paddr i2pkeys.I2PAddr
|
||||
var host string
|
||||
host, _, err = net.SplitHostPort(addr)
|
||||
if err == nil {
|
||||
@ -167,7 +169,7 @@ func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
|
||||
i2paddr, err = s.Lookup(host)
|
||||
} else {
|
||||
// probably a destination
|
||||
i2paddr = I2PAddr(host)
|
||||
i2paddr = i2pkeys.I2PAddr(host)
|
||||
}
|
||||
if err == nil {
|
||||
return s.DialI2P(i2paddr)
|
||||
@ -177,7 +179,7 @@ func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
|
||||
}
|
||||
|
||||
// Dials to an I2P destination and returns a SAMConn, which implements a net.Conn.
|
||||
func (s *StreamSession) DialI2P(addr I2PAddr) (*SAMConn, error) {
|
||||
func (s *StreamSession) DialI2P(addr i2pkeys.I2PAddr) (*SAMConn, error) {
|
||||
sam, err := NewSAM(s.samAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -203,7 +205,7 @@ func (s *StreamSession) DialI2P(addr I2PAddr) (*SAMConn, error) {
|
||||
case "STATUS":
|
||||
continue
|
||||
case "RESULT=OK":
|
||||
return &SAMConn{s.keys.addr, addr, conn}, nil
|
||||
return &SAMConn{s.keys.Address, addr, conn}, nil
|
||||
case "RESULT=CANT_REACH_PEER":
|
||||
conn.Close()
|
||||
return nil, errors.New("Can not reach peer")
|
||||
@ -242,7 +244,7 @@ type StreamListener struct {
|
||||
// our session id
|
||||
id string
|
||||
// our local address for this sam socket
|
||||
laddr I2PAddr
|
||||
laddr i2pkeys.I2PAddr
|
||||
}
|
||||
|
||||
// get our address
|
||||
@ -281,7 +283,7 @@ func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
|
||||
dest = strings.Trim(dest, "\n")
|
||||
return &SAMConn{
|
||||
laddr: l.laddr,
|
||||
raddr: I2PAddr(dest),
|
||||
raddr: i2pkeys.I2PAddr(dest),
|
||||
conn: s.conn,
|
||||
}, nil
|
||||
} else {
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
func Test_StreamingDial(t *testing.T) {
|
||||
@ -222,7 +224,7 @@ func ExampleStreamListener() {
|
||||
quit := make(chan bool)
|
||||
|
||||
// Client connecting to the server
|
||||
go func(server I2PAddr) {
|
||||
go func(server i2pkeys.I2PAddr) {
|
||||
csam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
|
Reference in New Issue
Block a user