github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/niaucchi4/obfssocket.go (about)

     1  package niaucchi4
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net"
     7  	"os"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/hashicorp/golang-lru/simplelru"
    12  	"github.com/patrickmn/go-cache"
    13  )
    14  
    15  var doLogging = false
    16  
    17  func init() {
    18  	doLogging = os.Getenv("N4LOG") != ""
    19  }
    20  
    21  type oAddr []byte
    22  
    23  func (sa oAddr) Network() string {
    24  	return "o-sess"
    25  }
    26  
    27  func (sa oAddr) String() string {
    28  	return fmt.Sprintf("osid-%x", []byte(sa)[:10])
    29  }
    30  
    31  // ObfsSocket represents an obfuscated PacketConn.
    32  type ObfsSocket struct {
    33  	cookie           []byte
    34  	cookieExceptions sync.Map
    35  	sscache          *simplelru.LRU
    36  	tunnels          *simplelru.LRU
    37  	pending          *simplelru.LRU
    38  	wire             net.PacketConn
    39  	wlock            sync.Mutex
    40  	rdbuf            [65536]byte
    41  	replayProtection bool
    42  }
    43  
    44  func newLRU() *simplelru.LRU {
    45  	l, e := simplelru.NewLRU(65536, nil)
    46  	if e != nil {
    47  		panic(e)
    48  	}
    49  	return l
    50  }
    51  
    52  // ObfsListen opens a new obfuscated PacketConn.
    53  func ObfsListen(cookie []byte, wire net.PacketConn, replayProtection bool) *ObfsSocket {
    54  	return &ObfsSocket{
    55  		cookie:           cookie,
    56  		sscache:          newLRU(),
    57  		tunnels:          newLRU(),
    58  		pending:          newLRU(),
    59  		wire:             wire,
    60  		replayProtection: replayProtection,
    61  	}
    62  }
    63  
    64  // AddCookieException adds a cookie exception to a particular destination.
    65  func (os *ObfsSocket) AddCookieException(addr net.Addr, cookie []byte) {
    66  	os.cookieExceptions.Store(addr, cookie)
    67  }
    68  
    69  func (os *ObfsSocket) WriteTo(b []byte, addr net.Addr) (int, error) {
    70  	os.wlock.Lock()
    71  	defer os.wlock.Unlock()
    72  	var isHidden bool
    73  	switch addr.(type) {
    74  	case oAddr:
    75  		v, ok := os.sscache.Get(string(addr.(oAddr)))
    76  		if !ok {
    77  			return 0, nil
    78  		}
    79  		addr = v.(net.Addr)
    80  		isHidden = true
    81  	}
    82  	if tuni, ok := os.tunnels.Get(addr.String()); ok {
    83  		tun := tuni.(*tunstate)
    84  		toWrite := tun.Encrypt(b)
    85  		_, err := os.wire.WriteTo(toWrite, addr)
    86  		if err != nil {
    87  			return 0, nil
    88  		}
    89  		return len(b), nil
    90  	}
    91  	if isHidden {
    92  		return 0, nil
    93  	}
    94  	// if we are pending, just ignore
    95  	if zz, ok := os.pending.Get(addr.String()); ok {
    96  		os.wire.WriteTo(zz.(*prototun).genHello(), addr)
    97  		if doLogging {
    98  			log.Println("N4: retransmitting existing pending to", addr.String())
    99  		}
   100  		return len(b), nil
   101  	}
   102  	// establish a conn
   103  	cookie := os.cookie
   104  	if v, ok := os.cookieExceptions.Load(addr); ok {
   105  		cookie = v.([]byte)
   106  	}
   107  	pt := newproto(cookie)
   108  	if doLogging {
   109  		log.Printf("N4: newproto on %v [%x]", addr.String(), cookie)
   110  	}
   111  	os.pending.Add(addr.String(), pt)
   112  	var err error
   113  	_, err = os.wire.WriteTo(pt.genHello(), addr)
   114  	if err != nil {
   115  		return 0, nil
   116  	}
   117  	return len(b), nil
   118  }
   119  
   120  func (os *ObfsSocket) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
   121  	for n == 0 && err == nil {
   122  		n, addr, err = os.hiddenReadFrom(b)
   123  	}
   124  	return
   125  }
   126  
   127  var badHelloBlacklist = cache.New(time.Minute*5, time.Minute)
   128  
   129  func (os *ObfsSocket) hiddenReadFrom(p []byte) (n int, addr net.Addr, err error) {
   130  	readBytes, addr, err := os.wire.ReadFrom(os.rdbuf[:])
   131  	if err != nil {
   132  		return
   133  	}
   134  	if _, ok := badHelloBlacklist.Get(addr.String()); ok {
   135  		return
   136  	}
   137  	os.wlock.Lock()
   138  	defer os.wlock.Unlock()
   139  	// check if the packet belongs to a known tunnel
   140  	if tuni, ok := os.tunnels.Get(addr.String()); ok {
   141  		tun := tuni.(*tunstate)
   142  		plain, e := tun.Decrypt(os.rdbuf[:readBytes])
   143  		if e == nil {
   144  			os.tunnels.Add(addr.String(), tun)
   145  			n = copy(p, plain)
   146  			if _, ok := os.sscache.Get(string(tun.ss)); ok {
   147  				os.sscache.Add(string(tun.ss), addr)
   148  				addr = oAddr(tun.ss)
   149  			}
   150  			return
   151  		}
   152  	}
   153  	// check if the packet belongs to a pending thing
   154  	if proti, ok := os.pending.Get(addr.String()); ok {
   155  		prot := proti.(*prototun)
   156  		ts, e := prot.realize(os.rdbuf[:readBytes], false, os.replayProtection)
   157  		if e != nil {
   158  			return
   159  		}
   160  		os.tunnels.Add(addr.String(), ts)
   161  		if doLogging {
   162  			log.Println("N4: got realization of pending", addr)
   163  		}
   164  		return
   165  	}
   166  	// iterate through all the stuff to create an association
   167  	for _, k := range os.tunnels.Keys() {
   168  		v, ok := os.tunnels.Get(k)
   169  		if !ok {
   170  			continue
   171  		}
   172  		tun := v.(*tunstate)
   173  		plain, e := tun.Decrypt(os.rdbuf[:readBytes])
   174  		if e == nil {
   175  			os.tunnels.Remove(k)
   176  			if doLogging {
   177  				log.Println("N4: found a decryptable session through scanning, ROAM to", addr)
   178  			}
   179  			os.tunnels.Add(addr.String(), tun)
   180  			n = copy(p, plain)
   181  			if _, ok := os.sscache.Get(string(tun.ss)); ok {
   182  				os.sscache.Add(string(tun.ss), addr)
   183  				addr = oAddr(tun.ss)
   184  			}
   185  			return
   186  		}
   187  	}
   188  	// otherwise it has to be some sort of tunnel opener
   189  	//log.Println("got suspected hello")
   190  	pt := newproto(os.cookie)
   191  	ts, e := pt.realize(os.rdbuf[:readBytes], true, os.replayProtection)
   192  	if e != nil {
   193  		if doLogging {
   194  			log.Println("N4: bad hello from", addr.String(), e.Error())
   195  		}
   196  		badHelloBlacklist.SetDefault(addr.String(), true)
   197  		return
   198  	}
   199  	os.tunnels.Add(addr.String(), ts)
   200  	os.sscache.Add(string(ts.ss), addr)
   201  	go func() {
   202  		os.wlock.Lock()
   203  		defer os.wlock.Unlock()
   204  		os.wire.WriteTo(pt.genHello(), addr)
   205  		if doLogging {
   206  			log.Println("N4: responded to a hello from", addr)
   207  		}
   208  	}()
   209  	return
   210  }
   211  
   212  func (os *ObfsSocket) Close() error {
   213  	return os.wire.Close()
   214  }
   215  
   216  func (os *ObfsSocket) LocalAddr() net.Addr {
   217  	return os.wire.LocalAddr()
   218  }
   219  
   220  func (os *ObfsSocket) SetDeadline(t time.Time) error {
   221  	return os.wire.SetDeadline(t)
   222  }
   223  
   224  func (os *ObfsSocket) SetReadDeadline(t time.Time) error {
   225  	return os.wire.SetReadDeadline(t)
   226  }
   227  func (os *ObfsSocket) SetWriteDeadline(t time.Time) error {
   228  	return os.wire.SetWriteDeadline(t)
   229  }