Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
cda19e0e82 | |||
5010986b65 | |||
b216e9fc86 | |||
f10e74f03a | |||
900f5393ad | |||
633a864a02 | |||
9cbfbcd4c7 | |||
2a96d0ea8f | |||
5f80e35560 | |||
6848baecce | |||
0891cbffe0 | |||
c8548ec53a | |||
a439c971e8 | |||
25363e06ac | |||
d2ace7d0b9 | |||
de00b9a871 | |||
e2a92ffa47 | |||
77ccfe94f3 | |||
b4236a4201 | |||
f1194c38b3 | |||
cfdb60d932 | |||
6eca8863f7 | |||
40ad754b47 | |||
6aed9d7cec | |||
35e4ae3c89 | |||
564a060ed3 | |||
62cade9ebc | |||
ca305ba46c | |||
25eb54b2bc | |||
86009cc805 | |||
1fc3dc5a20 | |||
a2fcfb8bc1 | |||
0623ed8a79 | |||
964219c25f | |||
23c45022b3 | |||
c6d9c0e340 | |||
460926afe8 | |||
e278de3a66 | |||
d1d2663c42 | |||
5af3086205 | |||
f97683379f | |||
42d542dd8b | |||
d94d9c4da0 | |||
dddd8ea916 | |||
b864407cc2 | |||
646767e7bf | |||
76e1e9af83 | |||
6bd37c4d51 | |||
e2f73efb10 | |||
5fda56e88d | |||
63833f24ab | |||
0d10b5b516 | |||
38ca0d08e7 | |||
a9bf9faba1 | |||
3c6a72d179 | |||
e8b7525950 | |||
a0407fd3e3 | |||
3c5397e87f | |||
9baee36493 | |||
379de14264 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,3 +23,6 @@ _testmain.go
|
||||
itp-golang-github-eyedeekay-gosam.txt
|
||||
.pc
|
||||
deb/
|
||||
samsocks/samsocks
|
||||
*.private
|
||||
*.public.txt
|
357
CONTRIBUTING.html
Normal file
357
CONTRIBUTING.html
Normal file
@ -0,0 +1,357 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
goSam
|
||||
</title>
|
||||
<meta name="author" content="eyedeekay" />
|
||||
<meta name="description" content="goSam" />
|
||||
<meta name="keywords" content="master" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
<a href="#shownav">
|
||||
Show navigation
|
||||
</a>
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="CONTRIBUTING.html">
|
||||
CONTRIBUTING
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<a href="#hidenav">
|
||||
Hide Navigation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a id="returnhome" href="/">
|
||||
/
|
||||
</a>
|
||||
<h1>
|
||||
How to make contributions to goSam
|
||||
</h1>
|
||||
<p>
|
||||
Welcome to goSam, the easy-to-use http client for i2p. We’re glad you’re here
|
||||
and interested in contributing. Here’s some help getting started.
|
||||
</p>
|
||||
<h2>
|
||||
Table of Contents
|
||||
</h2>
|
||||
<ul>
|
||||
<li>
|
||||
(1) Environment
|
||||
</li>
|
||||
<li>
|
||||
(2) Testing
|
||||
</li>
|
||||
<li>
|
||||
(3) Filing Issues/Reporting Bugs/Making Suggestions
|
||||
</li>
|
||||
<li>
|
||||
(4) Contributing Code/Style Guide
|
||||
<ul>
|
||||
<li>
|
||||
(a) Adding i2cp and tunnel Options
|
||||
</li>
|
||||
<li>
|
||||
(b) Writing Tests
|
||||
</li>
|
||||
<li>
|
||||
© Style
|
||||
</li>
|
||||
<li>
|
||||
(d) Other kinds of modification?
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
(5) Conduct
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
(1) Environment
|
||||
</h3>
|
||||
<p>
|
||||
goSam is a simple go library. You are free to use an IDE if you wish, but all
|
||||
that is required to build and test the library are a go compiler and the gofmt
|
||||
tool. Git is the version control system. All the files in the library are in a
|
||||
single root directory. Invoking go build from this directory not generate any
|
||||
files.
|
||||
</p>
|
||||
<h3>
|
||||
(2) Testing
|
||||
</h3>
|
||||
<p>
|
||||
Tests are implemented using the standard go “testing” library in files named
|
||||
“file_test.go,” so tests of the client go in client_test.go, name lookups
|
||||
in naming_test.go, et cetera. Everything that can be tested, should be tested.
|
||||
</p>
|
||||
<p>
|
||||
Testing is done by running
|
||||
</p>
|
||||
<pre><code> go test
|
||||
</code></pre>
|
||||
<p>
|
||||
More information about designing tests is below in the
|
||||
<strong>
|
||||
Contributing Code/Style Guide
|
||||
</strong>
|
||||
section below.
|
||||
</p>
|
||||
<h3>
|
||||
(3) Filing issues/Reporting bugs/Making suggestions
|
||||
</h3>
|
||||
<p>
|
||||
If you discover the library doing something you don’t think is right, please let
|
||||
us know! Just filing an issue here is OK.
|
||||
</p>
|
||||
<p>
|
||||
If you need to suggest a feature, we’re happy to hear from you too. Filing an
|
||||
issue will give us a place to discuss how it’s implemented openly and publicly.
|
||||
</p>
|
||||
<p>
|
||||
Please file an issue for your new code contributions in order to provide us with
|
||||
a place to discuss them for inclusion.
|
||||
</p>
|
||||
<h3>
|
||||
(4) Contributing Code/Style Guide
|
||||
</h3>
|
||||
<p>
|
||||
Welcome new coders. We have good news for you, this library is really easy to
|
||||
contribute to. The easiest contributions take the form of i2cp and tunnel
|
||||
options.
|
||||
</p>
|
||||
<h4>
|
||||
(a) Adding i2cp and tunnel Options
|
||||
</h4>
|
||||
<p>
|
||||
First, add a variable to store the state of your new option. For example, the
|
||||
existing variables are in the Client class
|
||||
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/client.go#L29">
|
||||
here:
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
i2cp and tunnel options are added in a highly uniform process of basically three
|
||||
steps. First, you create a functional argument in the options.go file, in the
|
||||
form:
|
||||
</p>
|
||||
<pre><code class="language-Go"> // SetOPTION sets $OPTION
|
||||
func SetOPTION(arg type) func(*Client) error { // arg type
|
||||
return func(c *Client) error { // pass a client to the inner function and declare error return function
|
||||
if arg == valid { // validate the argument
|
||||
c.option = s // set the variable to the argument value
|
||||
return nil // if option is set successfully return nil error
|
||||
}
|
||||
return fmt.Errorf("Invalid argument:" arg) // return a descriptive error if arg is invalid
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>
|
||||
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L187">
|
||||
example
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
Next, you create a getter which prepares the option. Regardless of the type of
|
||||
option that is set, these must return strings representing valid i2cp options.
|
||||
</p>
|
||||
<pre><code class="language-Go"> //return the OPTION as a string.
|
||||
func (c *Client) option() string {
|
||||
return fmt.Sprintf("i2cp.option=%d", c.option)
|
||||
}
|
||||
</code></pre>
|
||||
<p>
|
||||
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L299">
|
||||
example
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
Lastly, you’ll need to add it to the allOptions function and the
|
||||
Client.NewClient() function. To add it to allOptions, it looks like this:
|
||||
</p>
|
||||
<pre><code class="language-Go"> //return all options as string ready for passing to sendcmd
|
||||
func (c *Client) allOptions() string {
|
||||
return c.inlength() + " " +
|
||||
c.outlength() + " " +
|
||||
... //other options removed from example for brevity
|
||||
c.option()
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-Go"> //return all options as string ready for passing to sendcmd
|
||||
func (c *Client) NewClient() (*Client, error) {
|
||||
return NewClientFromOptions(
|
||||
SetHost(c.host),
|
||||
SetPort(c.port),
|
||||
... //other options removed from example for brevity
|
||||
SetCompression(c.compression),
|
||||
setlastaddr(c.lastaddr),
|
||||
setid(c.id),
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
<p>
|
||||
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L333">
|
||||
example
|
||||
</a>
|
||||
</p>
|
||||
<h4>
|
||||
(b) Writing Tests
|
||||
</h4>
|
||||
<p>
|
||||
Before the feature can be added, you’ll need to add a test for it to
|
||||
options_test.go. To do this, just add your new option to the long TestOptions
|
||||
functions in options_test.go.
|
||||
</p>
|
||||
<pre><code class="language-Go"> func TestOptionHost(t *testing.T) {
|
||||
client, err := NewClientFromOptions(
|
||||
SetHost("127.0.0.1"),
|
||||
SetPort("7656"),
|
||||
... //other options removed from example for brevity
|
||||
SetCloseIdleTime(300001),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
if result, err := client.validCreate(); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionPortInt(t *testing.T) {
|
||||
client, err := NewClientFromOptions(
|
||||
SetHost("127.0.0.1"),
|
||||
SetPortInt(7656),
|
||||
... //other options removed from example for brevity
|
||||
SetUnpublished(true),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
if result, err := client.validCreate(); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
<p>
|
||||
If any of these tasks fail, then the test should fail.
|
||||
</p>
|
||||
<h4>
|
||||
© Style
|
||||
</h4>
|
||||
<p>
|
||||
It’s pretty simple to make sure the code style is right, just run gofmt over it
|
||||
to adjust the indentation, and golint over it to ensure that your comments are
|
||||
of the correct form for the documentation generator.
|
||||
</p>
|
||||
<h4>
|
||||
(d) Other kinds of modification?
|
||||
</h4>
|
||||
<p>
|
||||
It may be useful to extend goSam in other ways. Since there’s not a
|
||||
one-size-fits-all uniform way of dealing with these kinds of changes, open an
|
||||
issue for discussion and
|
||||
</p>
|
||||
<h3>
|
||||
(5) Conduct
|
||||
</h3>
|
||||
<p>
|
||||
This is a small-ish, straightforward library intended to enable a clear
|
||||
technical task. We should be able to be civil with eachother, and give and
|
||||
accept criticism contructively and respectfully.
|
||||
</p>
|
||||
<p>
|
||||
This document was drawn from the examples given by Mozilla
|
||||
<a href="mozillascience.github.io/working-open-workshop/contributing/">
|
||||
here
|
||||
</a>
|
||||
</p>
|
||||
<div id="sourcecode">
|
||||
<span id="sourcehead">
|
||||
<strong>
|
||||
Get the source code:
|
||||
</strong>
|
||||
</span>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/goSam">
|
||||
Source Repository: (https://github.com/eyedeekay/goSam)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
</a>
|
||||
<div id="show">
|
||||
<div id="hide">
|
||||
<pre><code>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Henry
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
</code></pre>
|
||||
<a href="#hide">
|
||||
Hide license
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://geti2p.net/">
|
||||
<img src="i2plogo.png"></img>
|
||||
I2P
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
6
Makefile
6
Makefile
@ -1,16 +1,16 @@
|
||||
|
||||
USER_GH=eyedeekay
|
||||
VERSION=0.32.28
|
||||
VERSION=0.32.7
|
||||
packagename=gosam
|
||||
|
||||
echo: fmt
|
||||
@echo "type make version to do release $(VERSION)"
|
||||
|
||||
version:
|
||||
gothub release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
|
||||
github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
|
||||
|
||||
del:
|
||||
gothub delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
||||
github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
||||
|
||||
tar:
|
||||
tar --exclude .git \
|
||||
|
99
README.md
99
README.md
@ -3,10 +3,11 @@ goSam
|
||||
|
||||
A go library for using the [I2P](https://geti2p.net/en/) Simple Anonymous
|
||||
Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge. It
|
||||
has support for SAM version 3.1 signature types.
|
||||
has support for all streaming features SAM version 3.2.
|
||||
|
||||
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days. I am primarily maintaining functionality. This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of testing and no breaking changes to the API are expected.
|
||||
|
||||
|
||||
This is in an **early development stage**. I would love to hear about any
|
||||
issues or ideas for improvement.
|
||||
|
||||
## Installation
|
||||
```
|
||||
@ -15,7 +16,7 @@ go get github.com/eyedeekay/goSam
|
||||
|
||||
## Using it for HTTP Transport
|
||||
|
||||
I implemented `Client.Dial` like `net.Dial` so you can use go's library packages like http.
|
||||
`Client.Dial` implements `net.Dial` so you can use go's library packages like http.
|
||||
|
||||
```go
|
||||
package main
|
||||
@ -26,7 +27,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/cryptix/goSam"
|
||||
"github.com/eyedeekay/goSam"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -68,6 +69,93 @@ func checkErr(err error) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Using SAM by default, as a proxy for all HTTP Clients used by a Go application
|
||||
|
||||
This will make the SAM transport dialer the default for all HTTP clients.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/eyedeekay/goSam"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sam, err := goSam.NewDefaultClient()
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: sam.Dial,
|
||||
},
|
||||
}
|
||||
|
||||
http.DefaultClient = httpClient
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using it as a SOCKS proxy
|
||||
|
||||
`client` also implements a resolver compatible with
|
||||
[`getlantern/go-socks5`](https://github.com/getlantern/go-socks5),
|
||||
making it very easy to implement a SOCKS5 server.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/eyedeekay/goSam"
|
||||
"github.com/getlantern/go-socks5"
|
||||
"log"
|
||||
)
|
||||
|
||||
var (
|
||||
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||
)
|
||||
|
||||
func main() {
|
||||
sam, err := goSam.NewClient(*samaddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
conf := &socks5.Config{
|
||||
Dial: sam.DialContext,
|
||||
Resolver: sam,
|
||||
}
|
||||
server, err := socks5.New(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create SOCKS5 proxy on localhost port 8000
|
||||
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .deb package
|
||||
@ -92,3 +180,4 @@ similar systems.
|
||||
* Implement `STREAM FORWARD`
|
||||
* Implement datagrams (Repliable and Anon)
|
||||
|
||||
|
||||
|
@ -24,15 +24,14 @@ func (c *Client) Listen() (net.Listener, error) {
|
||||
// with Accept
|
||||
func (c *Client) ListenI2P(dest string) (net.Listener, error) {
|
||||
var err error
|
||||
c.id = c.NewID()
|
||||
c.destination, err = c.CreateStreamSession(c.id, dest)
|
||||
c.destination, err = c.CreateStreamSession(dest)
|
||||
d := c.destination
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("Listening on destination:", c.Base32()+".b32.i2p")
|
||||
|
||||
c, err = c.NewClient()
|
||||
c, err = c.NewClient(c.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -52,7 +51,7 @@ func (c *Client) Accept() (net.Conn, error) {
|
||||
if c.id == 0 {
|
||||
return c.AcceptI2P()
|
||||
}
|
||||
resp, err := c.StreamAccept(c.id)
|
||||
resp, err := c.StreamAccept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
47
auth.go
Normal file
47
auth.go
Normal file
@ -0,0 +1,47 @@
|
||||
package goSam
|
||||
|
||||
import "fmt"
|
||||
|
||||
// SetupAuth sends the AUTH ENABLE command and immediately sets up a new Username and
|
||||
// Password from the arguments
|
||||
func (c *Client) SetupAuth(user, password string) error {
|
||||
r, err := c.sendCmd("AUTH ENABLE\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Topic != "AUTH" {
|
||||
return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r)
|
||||
}
|
||||
r, err = c.sendCmd("AUTH %s %s\n", user, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Topic != "AUTH" {
|
||||
return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TeardownAuth sends the AUTH DISABLE command but does not remove the Username and
|
||||
// Password from the client PasswordManager
|
||||
func (c *Client) TeardownAuth() error {
|
||||
r, err := c.sendCmd("AUTH DISABLE\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Topic != "AUTH" {
|
||||
return fmt.Errorf("TeardownAuth Unknown Reply: %+v\n", r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) RemoveAuthUser(user string) error {
|
||||
r, err := c.sendCmd("AUTH REMOVE %s\n", user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Topic != "AUTH" {
|
||||
return fmt.Errorf("RemoveAuthUser Unknown Reply: %+v\n", r)
|
||||
}
|
||||
return nil
|
||||
}
|
58
auth/main.go
Normal file
58
auth/main.go
Normal file
@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/eyedeekay/goSam"
|
||||
)
|
||||
|
||||
/**
|
||||
THIS is a freestanding test for SAMv3.2 AUTH commands using goSam. It's
|
||||
intended to be run separate from the other tests so that you don't accidentally end
|
||||
up setting SAM session passwords and leaving them in the PasswordManager if a test
|
||||
fails for some reason before you can remove them.
|
||||
**/
|
||||
|
||||
func main() {
|
||||
client, err := goSam.NewClientFromOptions()
|
||||
if err != nil {
|
||||
client, err = goSam.NewClientFromOptions(
|
||||
goSam.SetUser("user"),
|
||||
goSam.SetPass("password"),
|
||||
)
|
||||
fmt.Println("Looks like you restarted the I2P router before sending AUTH DISABLE.")
|
||||
fmt.Println("This probably means that your SAM Bridge is in a broken state where it can't")
|
||||
fmt.Println("accept HELLO or AUTH commands anymore. You should fix this by removing the")
|
||||
fmt.Println("sam.auth=true entry from sam.config.")
|
||||
err = client.TeardownAuth()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(err)
|
||||
panic(err)
|
||||
}
|
||||
err = client.SetupAuth("user", "password")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
client2, err := goSam.NewDefaultClient()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
conn, err := client2.Dial("", "idk.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
conn.Close()
|
||||
err = client.RemoveAuthUser("user")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//fmt.Println(r)
|
||||
err = client.TeardownAuth()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//r, err = client.NewDestination()
|
||||
}
|
81
client.go
81
client.go
@ -12,6 +12,10 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/eyedeekay/i2pkeys"
|
||||
//samkeys "github.com/eyedeekay/goSam/compat"
|
||||
)
|
||||
|
||||
// A Client represents a single Connection to the SAM bridge
|
||||
@ -20,9 +24,13 @@ type Client struct {
|
||||
port string
|
||||
fromport string
|
||||
toport string
|
||||
user string
|
||||
pass string
|
||||
|
||||
SamConn net.Conn
|
||||
rd *bufio.Reader
|
||||
SamConn net.Conn // Control socket
|
||||
SamDGConn net.PacketConn // Datagram socket
|
||||
rd *bufio.Reader
|
||||
// d *Client
|
||||
|
||||
sigType string
|
||||
destination string
|
||||
@ -51,12 +59,14 @@ type Client struct {
|
||||
compression bool
|
||||
|
||||
debug bool
|
||||
mutex sync.Mutex
|
||||
//NEVER, EVER modify lastaddr or id yourself. They are used internally only.
|
||||
lastaddr string
|
||||
id int32
|
||||
ml sync.Mutex
|
||||
id int32
|
||||
sammin int
|
||||
sammax int
|
||||
}
|
||||
|
||||
// SAMsigTypes is a slice of the available signature types
|
||||
var SAMsigTypes = []string{
|
||||
"SIGNATURE_TYPE=DSA_SHA1",
|
||||
"SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
||||
@ -65,6 +75,12 @@ var SAMsigTypes = []string{
|
||||
"SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
||||
}
|
||||
|
||||
var ValidSAMCommands = []string{
|
||||
"HELLO",
|
||||
"SESSION",
|
||||
"STREAM",
|
||||
}
|
||||
|
||||
var (
|
||||
i2pB64enc *base64.Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
|
||||
i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
|
||||
@ -80,9 +96,18 @@ func NewClient(addr string) (*Client, error) {
|
||||
return NewClientFromOptions(SetAddr(addr))
|
||||
}
|
||||
|
||||
func NewID() int32 {
|
||||
id := rand.Int31n(math.MaxInt32)
|
||||
fmt.Printf("Initializing new ID: %d\n", id)
|
||||
return id
|
||||
}
|
||||
|
||||
// NewID generates a random number to use as an tunnel name
|
||||
func (c *Client) NewID() int32 {
|
||||
return rand.Int31n(math.MaxInt32)
|
||||
if c.id == 0 {
|
||||
c.id = NewID()
|
||||
}
|
||||
return c.id
|
||||
}
|
||||
|
||||
// Destination returns the full destination of the local tunnel
|
||||
@ -126,11 +151,11 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
||||
c.port = "7656"
|
||||
c.inLength = 3
|
||||
c.inVariance = 0
|
||||
c.inQuantity = 1
|
||||
c.inQuantity = 3
|
||||
c.inBackups = 1
|
||||
c.outLength = 3
|
||||
c.outVariance = 0
|
||||
c.outQuantity = 1
|
||||
c.outQuantity = 3
|
||||
c.outBackups = 1
|
||||
c.dontPublishLease = true
|
||||
c.encryptLease = false
|
||||
@ -139,20 +164,22 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
||||
c.reduceIdleQuantity = 1
|
||||
c.closeIdle = true
|
||||
c.closeIdleTime = 600000
|
||||
c.debug = true
|
||||
c.debug = false
|
||||
c.sigType = SAMsigTypes[4]
|
||||
c.id = 0
|
||||
c.lastaddr = "invalid"
|
||||
c.destination = ""
|
||||
c.leaseSetEncType = "4,0"
|
||||
c.fromport = ""
|
||||
c.toport = ""
|
||||
c.sammin = 0
|
||||
c.sammax = 1
|
||||
for _, o := range opts {
|
||||
if err := o(&c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
conn, err := net.Dial("tcp", c.samaddr())
|
||||
c.id = c.NewID()
|
||||
conn, err := net.DialTimeout("tcp", c.samaddr(), 15*time.Minute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -164,22 +191,37 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
||||
return &c, c.hello()
|
||||
}
|
||||
|
||||
// ID returns a the current ID of the client as a string
|
||||
func (p *Client) ID() string {
|
||||
return fmt.Sprintf("%d", p.id)
|
||||
return fmt.Sprintf("%d", p.NewID())
|
||||
}
|
||||
|
||||
// Addr returns the address of the client as a net.Addr
|
||||
func (p *Client) Addr() net.Addr {
|
||||
return nil
|
||||
keys := i2pkeys.I2PAddr(p.Destination())
|
||||
return keys
|
||||
}
|
||||
|
||||
//return the combined host:port of the SAM bridge
|
||||
func (p *Client) LocalAddr() net.Addr {
|
||||
return p.Addr()
|
||||
}
|
||||
|
||||
// LocalKeys returns the local keys of the client as a fully-fledged i2pkeys.I2PKeys
|
||||
func (p *Client) PrivateAddr() i2pkeys.I2PKeys {
|
||||
//keys := i2pkeys.I2PAddr(p.Destination())
|
||||
keys := i2pkeys.NewKeys(i2pkeys.I2PAddr(p.base64()), p.Destination())
|
||||
return keys
|
||||
}
|
||||
|
||||
// return the combined host:port of the SAM bridge
|
||||
func (c *Client) samaddr() string {
|
||||
return fmt.Sprintf("%s:%s", c.host, c.port)
|
||||
}
|
||||
|
||||
// send the initial handshake command and check that the reply is ok
|
||||
func (c *Client) hello() error {
|
||||
r, err := c.sendCmd("HELLO VERSION MIN=3.0 MAX=3.2\n")
|
||||
|
||||
r, err := c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s %s\n", c.sammin, c.sammax, c.getUser(), c.getPass())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -215,8 +257,10 @@ func (c *Client) Close() error {
|
||||
return c.SamConn.Close()
|
||||
}
|
||||
|
||||
// NewClient generates an exact copy of the client with the same options
|
||||
func (c *Client) NewClient() (*Client, error) {
|
||||
// NewClient generates an exact copy of the client with the same options, but
|
||||
// re-does all the handshaky business so that Dial can pick up right where it
|
||||
// left off, should the need arise.
|
||||
func (c *Client) NewClient(id int32) (*Client, error) {
|
||||
return NewClientFromOptions(
|
||||
SetHost(c.host),
|
||||
SetPort(c.port),
|
||||
@ -237,7 +281,6 @@ func (c *Client) NewClient() (*Client, error) {
|
||||
SetCloseIdle(c.closeIdle),
|
||||
SetCloseIdleTime(c.closeIdleTime),
|
||||
SetCompression(c.compression),
|
||||
setlastaddr(c.lastaddr),
|
||||
setid(c.id),
|
||||
setid(id),
|
||||
)
|
||||
}
|
||||
|
128
client_test.go
128
client_test.go
@ -1,3 +1,4 @@
|
||||
//go:build nettest
|
||||
// +build nettest
|
||||
|
||||
package goSam
|
||||
@ -6,84 +7,109 @@ import "testing"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
// "math"
|
||||
// "math/rand"
|
||||
// "time"
|
||||
//"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/eyedeekay/sam3"
|
||||
//"github.com/eyedeekay/sam3/helper"
|
||||
//"github.com/eyedeekay/i2pkeys"
|
||||
)
|
||||
|
||||
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
||||
}
|
||||
|
||||
var client *Client
|
||||
|
||||
func setup(t *testing.T) {
|
||||
var err error
|
||||
|
||||
// these tests expect a running SAM brige on this address
|
||||
client, err = NewClientFromOptions(SetDebug(true))
|
||||
if err != nil {
|
||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompositeClient(t *testing.T) {
|
||||
sam, err := sam3.NewSAM("127.0.0.1:7656")
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
stream, err := sam.NewStreamSession("serverTun", keys, sam3.Options_Medium)
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
listener, err := stream.Listen()
|
||||
/*func TestCompositeClient(t *testing.T) {
|
||||
listener, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys")
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
http.HandleFunc("/", HelloServer)
|
||||
go http.Serve(listener, nil)
|
||||
|
||||
client, err = NewClientFromOptions(SetDebug(true))
|
||||
listener2, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys2")
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
defer listener2.Close()
|
||||
// http.HandleFunc("/", HelloServer)
|
||||
go http.Serve(listener2, nil)
|
||||
|
||||
listener3, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys3")
|
||||
if err != nil {
|
||||
t.Fatalf("Listener() Error: %q\n", err)
|
||||
}
|
||||
defer listener3.Close()
|
||||
// http.HandleFunc("/", HelloServer)
|
||||
go http.Serve(listener3, nil)
|
||||
|
||||
sam, err := NewClientFromOptions(SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||
}
|
||||
tr := &http.Transport{
|
||||
Dial: client.Dial,
|
||||
Dial: sam.Dial,
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
time.Sleep(time.Second * 30)
|
||||
resp, err := client.Get("http://" + keys.Addr().Base32())
|
||||
if err != nil {
|
||||
t.Fatalf("Get Error: %q\n", err)
|
||||
defer sam.Close()
|
||||
x := 0
|
||||
for x < 15 {
|
||||
time.Sleep(time.Second * 2)
|
||||
t.Log("waiting a little while for services to register", (30 - (x * 2)))
|
||||
x++
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
t.Log("Get returned ", resp)
|
||||
time.Sleep(time.Second * 15)
|
||||
}
|
||||
go func() {
|
||||
resp, err := client.Get("http://" + listener.Addr().(i2pkeys.I2PAddr).Base32())
|
||||
if err != nil {
|
||||
t.Fatalf("Get Error test 1: %q\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}()
|
||||
//time.Sleep(time.Second * 15)
|
||||
go func() {
|
||||
resp, err := client.Get("http://" + listener2.Addr().(i2pkeys.I2PAddr).Base32())
|
||||
if err != nil {
|
||||
t.Fatalf("Get Error test 2: %q\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}()
|
||||
//time.Sleep(time.Second * 15)
|
||||
go func() {
|
||||
resp, err := client.Get("http://" + listener3.Addr().(i2pkeys.I2PAddr).Base32())
|
||||
if err != nil {
|
||||
t.Fatalf("Get Error test 3: %q\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}()
|
||||
|
||||
func teardown(t *testing.T) {
|
||||
time.Sleep(time.Second * 45)
|
||||
}*/
|
||||
|
||||
func TestClientHello(t *testing.T) {
|
||||
client, err := NewClientFromOptions(SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||
}
|
||||
t.Log(client.Base32())
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientHello(t *testing.T) {
|
||||
setup(t)
|
||||
t.Log(client.Base32())
|
||||
teardown(t)
|
||||
}
|
||||
|
||||
func TestNewDestination(t *testing.T) {
|
||||
setup(t)
|
||||
t.Log(client.Base32())
|
||||
if _, err := client.NewDestination(SAMsigTypes[3]); err != nil {
|
||||
t.Error(err)
|
||||
client, err := NewClientFromOptions(SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||
}
|
||||
t.Log(client.Base32())
|
||||
if s, p, err := client.NewDestination(SAMsigTypes[3]); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Log(s, p)
|
||||
}
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
teardown(t)
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package samkeys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func DestToKeys(dest string) (i2pkeys.I2PKeys, error) {
|
||||
addr, err := i2pkeys.NewI2PAddrFromString(dest)
|
||||
if err != nil {
|
||||
return i2pkeys.I2PKeys{}, err
|
||||
}
|
||||
return i2pkeys.NewKeys(addr, dest), nil
|
||||
}
|
||||
|
||||
func KeysToDest(keys i2pkeys.I2PKeys) (string, error) {
|
||||
pksk := strings.SplitN(keys.String(), "\n", 2)
|
||||
if len(pksk) != 2 {
|
||||
return "", fmt.Errorf("Error converting from keys to destination")
|
||||
}
|
||||
return pksk[1], nil
|
||||
}
|
9
conn.go
9
conn.go
@ -30,11 +30,14 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Conn Read data from the connection, writes data to te connection
|
||||
// and logs the data in-between.
|
||||
type Conn struct {
|
||||
RWC
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
// WrapConn wraps a net.Conn in a Conn.
|
||||
func WrapConn(c net.Conn) *Conn {
|
||||
wrap := Conn{
|
||||
conn: c,
|
||||
@ -45,23 +48,29 @@ func WrapConn(c net.Conn) *Conn {
|
||||
return &wrap
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address of the connection.
|
||||
func (c *Conn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address of the connection.
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated with the connection
|
||||
func (c *Conn) SetDeadline(t time.Time) error {
|
||||
log.Println("WARNING: SetDeadline() not sure this works")
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the read deadline associated with the connection
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
log.Println("WARNING: SetReadDeadline() not sure this works")
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the write deadline associated with the connection
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
log.Println("WARNING: SetWriteDeadline() not sure this works")
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
|
61
datagram.go
Normal file
61
datagram.go
Normal file
@ -0,0 +1,61 @@
|
||||
package goSam
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DatagramConn
|
||||
type DatagramConn struct {
|
||||
RWC
|
||||
conn net.PacketConn
|
||||
RAddr net.Addr
|
||||
}
|
||||
|
||||
// WrapConn wraps a net.PacketConn in a DatagramConn.
|
||||
func WrapPacketConn(c net.Conn) *Conn {
|
||||
wrap := Conn{
|
||||
conn: c,
|
||||
}
|
||||
wrap.Reader = NewReadLogger("<", c)
|
||||
wrap.Writer = NewWriteLogger(">", c)
|
||||
wrap.RWC.c = c
|
||||
return &wrap
|
||||
}
|
||||
|
||||
func (d *DatagramConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
return d.conn.ReadFrom(p)
|
||||
}
|
||||
func (d *DatagramConn) Read(b []byte) (n int, err error) {
|
||||
n, _, err = d.ReadFrom(b)
|
||||
return n, err
|
||||
}
|
||||
func (d *DatagramConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
return d.conn.WriteTo(p, addr)
|
||||
}
|
||||
func (d *DatagramConn) Write(b []byte) (n int, err error) {
|
||||
n, err = d.WriteTo(b, d.RemoteAddr())
|
||||
return n, err
|
||||
}
|
||||
func (d *DatagramConn) Close() error {
|
||||
return d.conn.Close()
|
||||
}
|
||||
func (d *DatagramConn) LocalAddr() net.Addr {
|
||||
return d.conn.LocalAddr()
|
||||
}
|
||||
func (d *DatagramConn) RemoteAddr() net.Addr {
|
||||
return d.RAddr
|
||||
}
|
||||
func (d *DatagramConn) SetDeadline(t time.Time) error {
|
||||
return d.conn.SetDeadline(t)
|
||||
}
|
||||
func (d *DatagramConn) SetReadDeadline(t time.Time) error {
|
||||
return d.conn.SetReadDeadline(t)
|
||||
}
|
||||
func (d *DatagramConn) SetWriteDeadline(t time.Time) error {
|
||||
return d.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
var dgt net.PacketConn = &DatagramConn{}
|
||||
|
||||
//func (c *Client) DatagramSend()
|
17
debian/changelog
vendored
17
debian/changelog
vendored
@ -1,4 +1,19 @@
|
||||
golang-github-eyedeekay-gosam (0.32.27) UNRELEASED; urgency=medium
|
||||
golang-github-eyedeekay-gosam (0.32.30) UNRELEASED; urgency=medium
|
||||
|
||||
* Improve the defaults
|
||||
* Handle errors more correctly
|
||||
* Gracefully handle hangups by creating a new session
|
||||
* Set empty destinations to TRANSIENT when dialing
|
||||
|
||||
-- idk <hankhill19580@gmail.com> Sun, 03 Nov 2020 16:12:04 -0500
|
||||
|
||||
golang-github-eyedeekay-gosam (0.32.29) UNRELEASED; urgency=medium
|
||||
|
||||
* Maintenance updates
|
||||
|
||||
-- idk <hankhill19580@gmail.com> Mon, 23 Nov 2020 20:40:40 -0500
|
||||
|
||||
golang-github-eyedeekay-gosam (0.32.28) UNRELEASED; urgency=medium
|
||||
|
||||
* Maintenance updates
|
||||
|
||||
|
54
dest.go
Normal file
54
dest.go
Normal file
@ -0,0 +1,54 @@
|
||||
package goSam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func validateKindInner(kind string) string {
|
||||
if strings.HasPrefix(kind, "SIGNATURE_TYPE=") {
|
||||
return kind
|
||||
}
|
||||
return "SIGNATURE_TYPE=" + kind
|
||||
}
|
||||
|
||||
func validateKind(kind string) (string, error) {
|
||||
//convert kind to int
|
||||
kint, err := strconv.Atoi(kind)
|
||||
if err != nil {
|
||||
for _, k := range SAMsigTypes {
|
||||
if strings.HasSuffix(k, kind) {
|
||||
return validateKindInner(kind), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if kint >= 0 && kint <= 7 {
|
||||
return validateKindInner(kind), nil
|
||||
}
|
||||
return "SIGNATURE_TYPE=7", fmt.Errorf("Invalid sigType: %s", kind)
|
||||
}
|
||||
|
||||
// Generate a new destination and return the base64 encoded string
|
||||
func (c *Client) NewDestination(kind ...string) (string, string, error) {
|
||||
if len(kind) == 0 {
|
||||
kind = []string{"7"}
|
||||
} else {
|
||||
var err error
|
||||
kind[0], err = validateKind(kind[0])
|
||||
if err != nil {
|
||||
if c.debug {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
r, err := c.sendCmd("DEST GENERATE %s\n", kind[0])
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if r.Topic != "DEST" {
|
||||
return "", "", fmt.Errorf("NewDestination Unknown Reply: %+v\n", r)
|
||||
}
|
||||
return r.Pairs["PRIV"], r.Pairs["PUB"], nil
|
||||
|
||||
}
|
81
dial.go
81
dial.go
@ -3,23 +3,23 @@ package goSam
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DialContext implements the net.DialContext function and can be used for http.Transport
|
||||
func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
errCh := make(chan error, 1)
|
||||
connCh := make(chan net.Conn, 1)
|
||||
go func() {
|
||||
if conn, err := c.Dial(network, addr); err != nil {
|
||||
if conn, err := c.DialContextFree(network, addr); err != nil {
|
||||
errCh <- err
|
||||
} else if ctx.Err() != nil {
|
||||
var err error
|
||||
c, err = c.NewClient()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
}
|
||||
log.Println(ctx)
|
||||
errCh <- ctx.Err()
|
||||
} else {
|
||||
connCh <- conn
|
||||
}
|
||||
@ -32,48 +32,69 @@ func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Con
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *Client) dialCheck(addr string) (int32, bool) {
|
||||
if c.lastaddr == "invalid" {
|
||||
fmt.Println("Preparing to dial new address.")
|
||||
return c.NewID(), true
|
||||
} else if c.lastaddr != addr {
|
||||
fmt.Println("Preparing to dial next new address.")
|
||||
return c.NewID(), true
|
||||
}
|
||||
return c.id, false
|
||||
}
|
||||
|
||||
// Dial implements the net.Dial function and can be used for http.Transport
|
||||
func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
||||
c.ml.Lock()
|
||||
defer c.ml.Unlock()
|
||||
return c.DialContext(context.TODO(), network, addr)
|
||||
}
|
||||
|
||||
// DialContextFree implements the net.Dial function and can be used for http.Transport
|
||||
func (c *Client) DialContextFree(network, addr string) (net.Conn, error) {
|
||||
if network == "tcp" || network == "tcp6" || network == "tcp4" {
|
||||
return c.DialStreamingContextFree(addr)
|
||||
}
|
||||
if network == "udp" || network == "udp6" || network == "udp4" {
|
||||
return c.DialDatagramContextFree(addr)
|
||||
}
|
||||
if network == "raw" || network == "ip" {
|
||||
return c.DialDatagramContextFree(addr)
|
||||
}
|
||||
return c.DialStreamingContextFree(addr)
|
||||
}
|
||||
|
||||
// DialDatagramContextFree is a "Dialer" for "Client-Like" Datagram connections.
|
||||
// It is also not finished. If you need datagram support right now, use sam3.
|
||||
func (c *Client) DialDatagramContextFree(addr string) (*DatagramConn, error) {
|
||||
portIdx := strings.Index(addr, ":")
|
||||
if portIdx >= 0 {
|
||||
addr = addr[:portIdx]
|
||||
}
|
||||
addr, err := c.Lookup(addr)
|
||||
if err != nil {
|
||||
log.Printf("LOOKUP DIALER ERROR %s %s", addr, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var test bool
|
||||
if c.id, test = c.dialCheck(addr); test == true {
|
||||
c.destination, err = c.CreateStreamSession(c.id, c.destination)
|
||||
return nil, fmt.Errorf("Datagram support is not finished yet, come back later`")
|
||||
}
|
||||
|
||||
// DialStreamingContextFree is a "Dialer" for "Client-Like" Streaming connections.
|
||||
func (c *Client) DialStreamingContextFree(addr string) (net.Conn, error) {
|
||||
portIdx := strings.Index(addr, ":")
|
||||
if portIdx >= 0 {
|
||||
addr = addr[:portIdx]
|
||||
}
|
||||
addr, err := c.Lookup(addr)
|
||||
if err != nil {
|
||||
log.Printf("LOOKUP DIALER ERROR %s %s", addr, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.destination == "" {
|
||||
c.destination, err = c.CreateStreamSession(c.destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.lastaddr = addr
|
||||
}
|
||||
c, err = c.NewClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.StreamConnect(c.id, addr)
|
||||
d, err := c.NewClient(c.NewID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.SamConn, nil
|
||||
err = d.StreamConnect(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.SamConn, nil
|
||||
}
|
||||
|
27
go.mod
27
go.mod
@ -1,11 +1,24 @@
|
||||
module github.com/eyedeekay/goSam
|
||||
|
||||
require github.com/eyedeekay/sam3 v0.32.2
|
||||
go 1.20
|
||||
|
||||
//replace github.com/eyedeekay/gosam v0.1.1-0.20190814195658-27e786578944 => github.com/eyedeekay/goSam ./
|
||||
require (
|
||||
github.com/eyedeekay/i2pkeys v0.33.0
|
||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5
|
||||
)
|
||||
|
||||
replace github.com/eyedeekay/gosam v0.32.1 => ./
|
||||
|
||||
replace github.com/eyedeekay/goSam v0.32.1 => ./
|
||||
|
||||
go 1.13
|
||||
require (
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
|
||||
github.com/getlantern/errors v1.0.1 // indirect
|
||||
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 // indirect
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
|
||||
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147 // indirect
|
||||
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd // indirect
|
||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
)
|
||||
|
95
go.sum
95
go.sum
@ -1,4 +1,91 @@
|
||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab h1:EfTRHxGSbiaEyxNzvKRBWVIDw3mD8xXGxj4gvwFzY7Q=
|
||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
|
||||
github.com/eyedeekay/sam3 v0.32.2 h1:xODDY5nBVg0oK7KaYk7ofkXFoHPsmI1umhSv1TZlS7s=
|
||||
github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eyedeekay/i2pkeys v0.33.0 h1:5SzUyWxNjV6AvYv/WaI8J4dSgAfv7/WEps6pDLe2YSs=
|
||||
github.com/eyedeekay/i2pkeys v0.33.0/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||
github.com/getlantern/errors v1.0.1 h1:XukU2whlh7OdpxnkXhNH9VTLVz0EVPGKDV5K0oWhvzw=
|
||||
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||
github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4 h1:JdD4XSaT6/j6InM7MT1E4WRvzR8gurxfq53A3ML3B/Q=
|
||||
github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4/go.mod h1:XZwE+iIlAgr64OFbXKFNCllBwV4wEipPx8Hlo2gZdbM=
|
||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5 h1:RBKofGGMt2k6eGBwX8mky9qunjL+KnAp9JdzXjiRkRw=
|
||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
|
||||
github.com/getlantern/golog v0.0.0-20210606115803-bce9f9fe5a5f/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
|
||||
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 h1:NlQedYmPI3pRAXJb+hLVVDGqfvvXGRPV8vp7XOjKAZ0=
|
||||
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65/go.mod h1:+ZU1h+iOVqWReBpky6d5Y2WL0sF2Llxu+QcxJFs2+OU=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147 h1:/4ibPEIbC7c786Ec5Z8QqTti8MAjjTp/LmfuF6frVDM=
|
||||
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147/go.mod h1:hfspzdRcvJ130tpTPL53/L92gG0pFtvQ6ln35ppwhHE=
|
||||
github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848 h1:2MhMMVBTnaHrst6HyWFDhwQCaJ05PZuOv1bE2gN8WFY=
|
||||
github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8=
|
||||
github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7 h1:03J6Cb42EG06lHgpOFGm5BOax4qFqlSbSeKO2RGrj2g=
|
||||
github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7/go.mod h1:GfzwugvtH7YcmNIrHHizeyImsgEdyL88YkdnK28B14c=
|
||||
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd h1:z5IehLDMqMwJ0oeFIaMHhySRU8r1lRMh7WQ0Wn0LioA=
|
||||
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd/go.mod h1:WEXF4pfIfnHBUAKwLa4DW7kcEINtG6wjUkbL2btwXZQ=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWSvoHI6ZatlG4B+GBDLxV/2ZkBsTA=
|
||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
35
i2pkeys.go
35
i2pkeys.go
@ -1,35 +0,0 @@
|
||||
package goSam
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/eyedeekay/sam3/i2pkeys"
|
||||
)
|
||||
|
||||
// NewDestination generates a new I2P destination, creating the underlying
|
||||
// public/private keys in the process. The public key can be used to send messages
|
||||
// to the destination, while the private key can be used to reply to messages
|
||||
func (c *Client) NewDestination(sigType ...string) (i2pkeys.I2PKeys, error) {
|
||||
var (
|
||||
sigtmp string
|
||||
keys i2pkeys.I2PKeys
|
||||
)
|
||||
if len(sigType) > 0 {
|
||||
sigtmp = sigType[0]
|
||||
}
|
||||
r, err := c.sendCmd(
|
||||
"DEST GENERATE %s\n",
|
||||
sigtmp,
|
||||
)
|
||||
if err != nil {
|
||||
return keys, err
|
||||
}
|
||||
var pub, priv string
|
||||
if priv = r.Pairs["PRIV"]; priv == "" {
|
||||
return keys, errors.New("failed to generate private destination key")
|
||||
}
|
||||
if pub = r.Pairs["PUB"]; pub == "" {
|
||||
return keys, errors.New("failed to generate public destination key")
|
||||
}
|
||||
return i2pkeys.NewKeys(i2pkeys.I2PAddr(pub), priv), nil
|
||||
}
|
BIN
i2plogo.png
Normal file
BIN
i2plogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
325
index.html
Normal file
325
index.html
Normal file
@ -0,0 +1,325 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
goSam
|
||||
</title>
|
||||
<meta name="author" content="eyedeekay" />
|
||||
<meta name="description" content="goSam" />
|
||||
<meta name="keywords" content="master" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
<a href="#shownav">
|
||||
Show navigation
|
||||
</a>
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="CONTRIBUTING.html">
|
||||
CONTRIBUTING
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<a href="#hidenav">
|
||||
Hide Navigation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a id="returnhome" href="/">
|
||||
/
|
||||
</a>
|
||||
<h1>
|
||||
goSam
|
||||
</h1>
|
||||
<p>
|
||||
A go library for using the
|
||||
<a href="https://geti2p.net/en/">
|
||||
I2P
|
||||
</a>
|
||||
Simple Anonymous
|
||||
Messaging (
|
||||
<a href="https://geti2p.net/en/docs/api/samv3">
|
||||
SAM version 3.0
|
||||
</a>
|
||||
) bridge. It
|
||||
has support for all streaming features SAM version 3.2.
|
||||
</p>
|
||||
<p>
|
||||
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days. I am primarily maintaining functionality. This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of testing and no breaking changes to the API are expected.
|
||||
</p>
|
||||
<h2>
|
||||
Installation
|
||||
</h2>
|
||||
<pre><code>go get github.com/eyedeekay/goSam
|
||||
</code></pre>
|
||||
<h2>
|
||||
Using it for HTTP Transport
|
||||
</h2>
|
||||
<p>
|
||||
<code>
|
||||
Client.Dial
|
||||
</code>
|
||||
implements
|
||||
<code>
|
||||
net.Dial
|
||||
</code>
|
||||
so you can use go’s library packages like http.
|
||||
</p>
|
||||
<pre><code class="language-go">package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/cryptix/goSam"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// create a default sam client
|
||||
sam, err := goSam.NewDefaultClient()
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
tr := &http.Transport{
|
||||
Dial: sam.Dial,
|
||||
}
|
||||
|
||||
// create a client using this transport
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
// send a get request
|
||||
resp, err := client.Get("http://stats.i2p/")
|
||||
checkErr(err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("Get returned %+v\n", resp)
|
||||
|
||||
// create a file for the response
|
||||
file, err := os.Create("stats.html")
|
||||
checkErr(err)
|
||||
defer file.Close()
|
||||
|
||||
// copy the response to the file
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Done.")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
<h3>
|
||||
Using SAM by default, as a proxy for all HTTP Clients used by a Go application
|
||||
</h3>
|
||||
<p>
|
||||
This will make the SAM transport dialer the default for all HTTP clients.
|
||||
</p>
|
||||
<pre><code class="language-go">package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/cryptix/goSam"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sam, err := goSam.NewDefaultClient()
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: sam.Dial,
|
||||
},
|
||||
}
|
||||
|
||||
http.DefaultClient = httpClient
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>
|
||||
Using it as a SOCKS proxy
|
||||
</h2>
|
||||
<p>
|
||||
<code>
|
||||
client
|
||||
</code>
|
||||
also implements a resolver compatible with
|
||||
<a href="https://github.com/getlantern/go-socks5">
|
||||
<code>
|
||||
getlantern/go-socks5
|
||||
</code>
|
||||
</a>
|
||||
,
|
||||
making it very easy to implement a SOCKS5 server.
|
||||
</p>
|
||||
<pre><code class="language-go">package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/eyedeekay/goSam"
|
||||
"github.com/getlantern/go-socks5"
|
||||
"log"
|
||||
)
|
||||
|
||||
var (
|
||||
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||
)
|
||||
|
||||
func main() {
|
||||
sam, err := goSam.NewClient(*samaddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
conf := &socks5.Config{
|
||||
Dial: sam.DialContext,
|
||||
Resolver: sam,
|
||||
}
|
||||
server, err := socks5.New(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create SOCKS5 proxy on localhost port 8000
|
||||
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h3>
|
||||
.deb package
|
||||
</h3>
|
||||
<p>
|
||||
A package for installing this on Debian is buildable, and a version for Ubuntu
|
||||
is available as a PPA and mirrored via i2p. To build the deb package, from the
|
||||
root of this repository with the build dependencies installed(git, i2p, go,
|
||||
debuild) run the command
|
||||
</p>
|
||||
<pre><code> debuild -us -uc
|
||||
</code></pre>
|
||||
<p>
|
||||
to produce an unsigned deb for personal use only. For packagers,
|
||||
</p>
|
||||
<pre><code> debuild -S
|
||||
</code></pre>
|
||||
<p>
|
||||
will produce a viable source package for use with Launchpad PPA’s and other
|
||||
similar systems.
|
||||
</p>
|
||||
<h3>
|
||||
TODO
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Improve recovery on failed sockets
|
||||
</li>
|
||||
<li>
|
||||
Implement
|
||||
<code>
|
||||
STREAM FORWARD
|
||||
</code>
|
||||
</li>
|
||||
<li>
|
||||
Implement datagrams (Repliable and Anon)
|
||||
</li>
|
||||
</ul>
|
||||
<div id="sourcecode">
|
||||
<span id="sourcehead">
|
||||
<strong>
|
||||
Get the source code:
|
||||
</strong>
|
||||
</span>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/goSam">
|
||||
Source Repository: (https://github.com/eyedeekay/goSam)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
</a>
|
||||
<div id="show">
|
||||
<div id="hide">
|
||||
<pre><code>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Henry
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
</code></pre>
|
||||
<a href="#hide">
|
||||
Hide license
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://geti2p.net/">
|
||||
<img src="i2plogo.png"></img>
|
||||
I2P
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
48
naming.go
48
naming.go
@ -17,7 +17,7 @@ func (c *Client) Lookup(name string) (string, error) {
|
||||
|
||||
// TODO: move check into sendCmd()
|
||||
if r.Topic != "NAMING" || r.Type != "REPLY" {
|
||||
return "", fmt.Errorf("Naming Unknown Reply: %+v\n", r)
|
||||
return "", fmt.Errorf("Naming Unknown Reply: %s, %s\n", r.Topic, r.Type)
|
||||
}
|
||||
|
||||
result := r.Pairs["RESULT"]
|
||||
@ -37,37 +37,39 @@ func (c *Client) Lookup(name string) (string, error) {
|
||||
}
|
||||
|
||||
func (c *Client) forward(client, conn net.Conn) {
|
||||
defer client.Close()
|
||||
defer conn.Close()
|
||||
go func() {
|
||||
defer client.Close()
|
||||
defer conn.Close()
|
||||
// defer client.Close()
|
||||
// defer conn.Close()
|
||||
io.Copy(client, conn)
|
||||
}()
|
||||
go func() {
|
||||
defer client.Close()
|
||||
defer conn.Close()
|
||||
// defer client.Close()
|
||||
// defer conn.Close()
|
||||
io.Copy(conn, client)
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *Client) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
|
||||
if c.lastaddr == "invalid" || c.lastaddr != name {
|
||||
client, err := c.DialContext(ctx, "", name)
|
||||
if err != nil {
|
||||
return ctx, nil, err
|
||||
}
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:")
|
||||
if err != nil {
|
||||
return ctx, nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
go c.forward(client, conn)
|
||||
}
|
||||
}()
|
||||
// if c.lastaddr == "invalid" || c.lastaddr != name {
|
||||
client, err := c.DialContext(ctx, "", name)
|
||||
if err != nil {
|
||||
return ctx, nil, err
|
||||
}
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:")
|
||||
if err != nil {
|
||||
return ctx, nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
go c.forward(client, conn)
|
||||
}
|
||||
}()
|
||||
// }
|
||||
return ctx, nil, nil
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build nettest
|
||||
// +build nettest
|
||||
|
||||
package goSam
|
||||
@ -10,8 +11,10 @@ import (
|
||||
func TestClientLookupInvalid(t *testing.T) {
|
||||
var err error
|
||||
|
||||
setup(t)
|
||||
defer teardown(t)
|
||||
client, err := NewClientFromOptions(SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||
}
|
||||
|
||||
addr, err := client.Lookup(`!(@#)`)
|
||||
if addr != "" || err == nil {
|
||||
@ -25,6 +28,9 @@ func TestClientLookupInvalid(t *testing.T) {
|
||||
if repErr.Result != ResultKeyNotFound {
|
||||
t.Errorf("client.Lookup() should throw an ResultKeyNotFound error.\nGot:%+v%s%s\n", repErr, "!=", ResultKeyNotFound)
|
||||
}
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientLookupValid(t *testing.T) {
|
||||
|
162
options.go
162
options.go
@ -6,10 +6,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
//Option is a client Option
|
||||
// Option is a client Option
|
||||
type Option func(*Client) error
|
||||
|
||||
//SetAddr sets a clients's address in the form host:port or host, port
|
||||
// SetAddr sets a clients's address in the form host:port or host, port
|
||||
func SetAddr(s ...string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if len(s) == 1 {
|
||||
@ -42,7 +42,7 @@ func SetAddr(s ...string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetAddrMixed sets a clients's address in the form host, port(int)
|
||||
// SetAddrMixed sets a clients's address in the form host, port(int)
|
||||
func SetAddrMixed(s string, i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 65536 && i > 0 {
|
||||
@ -54,7 +54,7 @@ func SetAddrMixed(s string, i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetHost sets the host of the client's SAM bridge
|
||||
// SetHost sets the host of the client's SAM bridge
|
||||
func SetHost(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.host = s
|
||||
@ -62,18 +62,53 @@ func SetHost(s string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetLocalDestination sets the local destination of the tunnel from a private
|
||||
//key
|
||||
func SetLocalDestination(s string) func(*Client) error {
|
||||
// SetUser sets the username for authentication during the SAM HELLO phase
|
||||
func SetUser(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.destination = s
|
||||
c.user = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func setlastaddr(s string) func(*Client) error {
|
||||
// SetUser sets the password for authentication during the SAM HELLO phase
|
||||
func SetPass(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.lastaddr = s
|
||||
c.pass = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetSAMMinVersion(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 0 {
|
||||
return fmt.Errorf("SAM version must be greater than or equal to 0")
|
||||
}
|
||||
if i > 3 {
|
||||
return fmt.Errorf("SAM version must be less than or equal to 3")
|
||||
}
|
||||
c.sammin = i
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetSAMMaxVersion(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 0 {
|
||||
return fmt.Errorf("SAM version must be greater than or equal to 0")
|
||||
}
|
||||
if i > 3 {
|
||||
return fmt.Errorf("SAM version must be less than or equal to 3")
|
||||
}
|
||||
c.sammin = i
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetLocalDestination sets the local destination of the tunnel from a private
|
||||
// key
|
||||
func SetLocalDestination(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.destination = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -85,7 +120,7 @@ func setid(s int32) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetPort sets the port of the client's SAM bridge using a string
|
||||
// SetPort sets the port of the client's SAM bridge using a string
|
||||
func SetPort(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
port, err := strconv.Atoi(s)
|
||||
@ -100,7 +135,7 @@ func SetPort(s string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetPortInt sets the port of the client's SAM bridge using a string
|
||||
// SetPortInt sets the port of the client's SAM bridge using a string
|
||||
func SetPortInt(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 65536 && i > -1 {
|
||||
@ -111,7 +146,7 @@ func SetPortInt(i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetFromPort sets the port of the client's SAM bridge using a string
|
||||
// SetFromPort sets the port of the client's SAM bridge using a string
|
||||
func SetFromPort(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
port, err := strconv.Atoi(s)
|
||||
@ -126,7 +161,7 @@ func SetFromPort(s string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetFromPortInt sets the port of the client's SAM bridge using a string
|
||||
// SetFromPortInt sets the port of the client's SAM bridge using a string
|
||||
func SetFromPortInt(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 65536 && i > -1 {
|
||||
@ -137,7 +172,7 @@ func SetFromPortInt(i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetToPort sets the port of the client's SAM bridge using a string
|
||||
// SetToPort sets the port of the client's SAM bridge using a string
|
||||
func SetToPort(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
port, err := strconv.Atoi(s)
|
||||
@ -152,7 +187,7 @@ func SetToPort(s string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetToPortInt sets the port of the client's SAM bridge using a string
|
||||
// SetToPortInt sets the port of the client's SAM bridge using a string
|
||||
func SetToPortInt(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 65536 && i > -1 {
|
||||
@ -163,15 +198,16 @@ func SetToPortInt(i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetDebug enables debugging messages
|
||||
// SetDebug enables debugging messages
|
||||
func SetDebug(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.debug = b
|
||||
//c.debug = b
|
||||
c.debug = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//SetInLength sets the number of hops inbound
|
||||
// SetInLength sets the number of hops inbound
|
||||
func SetInLength(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u < 7 {
|
||||
@ -182,7 +218,7 @@ func SetInLength(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutLength sets the number of hops outbound
|
||||
// SetOutLength sets the number of hops outbound
|
||||
func SetOutLength(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u < 7 {
|
||||
@ -193,7 +229,7 @@ func SetOutLength(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetInVariance sets the variance of a number of hops inbound
|
||||
// SetInVariance sets the variance of a number of hops inbound
|
||||
func SetInVariance(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 7 && i > -7 {
|
||||
@ -204,7 +240,7 @@ func SetInVariance(i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutVariance sets the variance of a number of hops outbound
|
||||
// SetOutVariance sets the variance of a number of hops outbound
|
||||
func SetOutVariance(i int) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if i < 7 && i > -7 {
|
||||
@ -215,7 +251,7 @@ func SetOutVariance(i int) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetInQuantity sets the inbound tunnel quantity
|
||||
// SetInQuantity sets the inbound tunnel quantity
|
||||
func SetInQuantity(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u <= 16 {
|
||||
@ -226,7 +262,7 @@ func SetInQuantity(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutQuantity sets the outbound tunnel quantity
|
||||
// SetOutQuantity sets the outbound tunnel quantity
|
||||
func SetOutQuantity(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u <= 16 {
|
||||
@ -237,7 +273,7 @@ func SetOutQuantity(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetInBackups sets the inbound tunnel backups
|
||||
// SetInBackups sets the inbound tunnel backups
|
||||
func SetInBackups(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u < 6 {
|
||||
@ -248,7 +284,7 @@ func SetInBackups(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetOutBackups sets the inbound tunnel backups
|
||||
// SetOutBackups sets the inbound tunnel backups
|
||||
func SetOutBackups(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u < 6 {
|
||||
@ -259,7 +295,7 @@ func SetOutBackups(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetUnpublished tells the router to not publish the client leaseset
|
||||
// SetUnpublished tells the router to not publish the client leaseset
|
||||
func SetUnpublished(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.dontPublishLease = b
|
||||
@ -267,7 +303,7 @@ func SetUnpublished(b bool) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetEncrypt tells the router to use an encrypted leaseset
|
||||
// SetEncrypt tells the router to use an encrypted leaseset
|
||||
func SetEncrypt(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.encryptLease = b
|
||||
@ -275,8 +311,8 @@ func SetEncrypt(b bool) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetLeaseSetEncType tells the router to use an encrypted leaseset of a specific type.
|
||||
//defaults to 4,0
|
||||
// SetLeaseSetEncType tells the router to use an encrypted leaseset of a specific type.
|
||||
// defaults to 4,0
|
||||
func SetLeaseSetEncType(b string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.leaseSetEncType = b
|
||||
@ -284,7 +320,7 @@ func SetLeaseSetEncType(b string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
|
||||
// SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
|
||||
func SetReduceIdle(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.reduceIdle = b
|
||||
@ -292,7 +328,7 @@ func SetReduceIdle(b bool) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
|
||||
// SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
|
||||
func SetReduceIdleTime(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u > 299999 {
|
||||
@ -303,7 +339,7 @@ func SetReduceIdleTime(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
|
||||
// SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
|
||||
func SetReduceIdleQuantity(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u < 5 {
|
||||
@ -314,7 +350,7 @@ func SetReduceIdleQuantity(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetCloseIdle sets the tunnels to close after a specific amount of time
|
||||
// SetCloseIdle sets the tunnels to close after a specific amount of time
|
||||
func SetCloseIdle(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.closeIdle = b
|
||||
@ -322,7 +358,7 @@ func SetCloseIdle(b bool) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetCloseIdleTime sets the time in milliseconds to wait before closing tunnels
|
||||
// SetCloseIdleTime sets the time in milliseconds to wait before closing tunnels
|
||||
func SetCloseIdleTime(u uint) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
if u > 299999 {
|
||||
@ -333,7 +369,7 @@ func SetCloseIdleTime(u uint) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//SetCompression sets the tunnels to close after a specific amount of time
|
||||
// SetCompression sets the tunnels to close after a specific amount of time
|
||||
func SetCompression(b bool) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
c.compression = b
|
||||
@ -343,13 +379,15 @@ func SetCompression(b bool) func(*Client) error {
|
||||
|
||||
/* SAM v 3.1 Options*/
|
||||
|
||||
//SetSignatureType tells gosam to pass SAM a signature_type parameter with one
|
||||
// SetSignatureType tells gosam to pass SAM a signature_type parameter with one
|
||||
// of the following values:
|
||||
// "SIGNATURE_TYPE=DSA_SHA1",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA384_P384",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA512_P521",
|
||||
// "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
||||
//
|
||||
// "SIGNATURE_TYPE=DSA_SHA1",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA384_P384",
|
||||
// "SIGNATURE_TYPE=ECDSA_SHA512_P521",
|
||||
// "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
||||
//
|
||||
// or an empty string
|
||||
func SetSignatureType(s string) func(*Client) error {
|
||||
return func(c *Client) error {
|
||||
@ -367,7 +405,7 @@ func SetSignatureType(s string) func(*Client) error {
|
||||
}
|
||||
}
|
||||
|
||||
//return the from port as a string.
|
||||
// return the from port as a string.
|
||||
func (c *Client) from() string {
|
||||
if c.fromport == "FROM_PORT=0" {
|
||||
return ""
|
||||
@ -381,7 +419,7 @@ func (c *Client) from() string {
|
||||
return fmt.Sprintf(" FROM_PORT=%v ", c.fromport)
|
||||
}
|
||||
|
||||
//return the to port as a string.
|
||||
// return the to port as a string.
|
||||
func (c *Client) to() string {
|
||||
if c.fromport == "TO_PORT=0" {
|
||||
return ""
|
||||
@ -395,47 +433,47 @@ func (c *Client) to() string {
|
||||
return fmt.Sprintf(" TO_PORT=%v ", c.toport)
|
||||
}
|
||||
|
||||
//return the signature type as a string.
|
||||
// return the signature type as a string.
|
||||
func (c *Client) sigtype() string {
|
||||
return fmt.Sprintf(" %s ", c.sigType)
|
||||
}
|
||||
|
||||
//return the inbound length as a string.
|
||||
// return the inbound length as a string.
|
||||
func (c *Client) inlength() string {
|
||||
return fmt.Sprintf(" inbound.length=%d ", c.inLength)
|
||||
}
|
||||
|
||||
//return the outbound length as a string.
|
||||
// return the outbound length as a string.
|
||||
func (c *Client) outlength() string {
|
||||
return fmt.Sprintf(" outbound.length=%d ", c.outLength)
|
||||
}
|
||||
|
||||
//return the inbound length variance as a string.
|
||||
// return the inbound length variance as a string.
|
||||
func (c *Client) invariance() string {
|
||||
return fmt.Sprintf(" inbound.lengthVariance=%d ", c.inVariance)
|
||||
}
|
||||
|
||||
//return the outbound length variance as a string.
|
||||
// return the outbound length variance as a string.
|
||||
func (c *Client) outvariance() string {
|
||||
return fmt.Sprintf(" outbound.lengthVariance=%d ", c.outVariance)
|
||||
}
|
||||
|
||||
//return the inbound tunnel quantity as a string.
|
||||
// return the inbound tunnel quantity as a string.
|
||||
func (c *Client) inquantity() string {
|
||||
return fmt.Sprintf(" inbound.quantity=%d ", c.inQuantity)
|
||||
}
|
||||
|
||||
//return the outbound tunnel quantity as a string.
|
||||
// return the outbound tunnel quantity as a string.
|
||||
func (c *Client) outquantity() string {
|
||||
return fmt.Sprintf(" outbound.quantity=%d ", c.outQuantity)
|
||||
}
|
||||
|
||||
//return the inbound tunnel quantity as a string.
|
||||
// return the inbound tunnel quantity as a string.
|
||||
func (c *Client) inbackups() string {
|
||||
return fmt.Sprintf(" inbound.backupQuantity=%d ", c.inQuantity)
|
||||
}
|
||||
|
||||
//return the outbound tunnel quantity as a string.
|
||||
// return the outbound tunnel quantity as a string.
|
||||
func (c *Client) outbackups() string {
|
||||
return fmt.Sprintf(" outbound.backupQuantity=%d ", c.outQuantity)
|
||||
}
|
||||
@ -494,7 +532,7 @@ func (c *Client) compresion() string {
|
||||
return " i2cp.gzip=false "
|
||||
}
|
||||
|
||||
//return all options as string ready for passing to sendcmd
|
||||
// return all options as string ready for passing to sendcmd
|
||||
func (c *Client) allOptions() string {
|
||||
return c.inlength() +
|
||||
c.outlength() +
|
||||
@ -515,7 +553,7 @@ func (c *Client) allOptions() string {
|
||||
c.compresion()
|
||||
}
|
||||
|
||||
//Print return all options as string
|
||||
// Print return all options as string
|
||||
func (c *Client) Print() string {
|
||||
return c.inlength() +
|
||||
c.outlength() +
|
||||
@ -535,3 +573,17 @@ func (c *Client) Print() string {
|
||||
c.closeidletime() +
|
||||
c.compresion()
|
||||
}
|
||||
|
||||
func (c *Client) getUser() string {
|
||||
if c.user == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("USER=%s", c.user)
|
||||
}
|
||||
|
||||
func (c *Client) getPass() string {
|
||||
if c.pass == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("PASSWORD=%s", c.pass)
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
//go:build nettest
|
||||
// +build nettest
|
||||
|
||||
package goSam
|
||||
|
||||
/*
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
@ -33,12 +32,12 @@ func (c *Client) validCmd(str string, args ...interface{}) (string, error) {
|
||||
|
||||
func (c *Client) validCreate() (string, error) {
|
||||
id := rand.Int31n(math.MaxInt32)
|
||||
result, err := c.validCmd("SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s\n", id, "abc.i2p", client.allOptions())
|
||||
result, err := c.validCmd("SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s\n", id, "abc.i2p", c.allOptions())
|
||||
return result, err
|
||||
}
|
||||
|
||||
func TestOptionAddrString(t *testing.T) {
|
||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(true))
|
||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
@ -47,17 +46,17 @@ func TestOptionAddrString(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
|
||||
func TestOptionAddrStringLh(t *testing.T) {
|
||||
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(true))
|
||||
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
@ -66,17 +65,17 @@ func TestOptionAddrStringLh(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
|
||||
func TestOptionAddrSlice(t *testing.T) {
|
||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(true))
|
||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
@ -85,17 +84,17 @@ func TestOptionAddrSlice(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
|
||||
func TestOptionAddrMixedSlice(t *testing.T) {
|
||||
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(true))
|
||||
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(false))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||
}
|
||||
@ -104,13 +103,13 @@ func TestOptionAddrMixedSlice(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
|
||||
func TestOptionHost(t *testing.T) {
|
||||
@ -126,7 +125,7 @@ func TestOptionHost(t *testing.T) {
|
||||
SetInBackups(2),
|
||||
SetOutBackups(2),
|
||||
SetEncrypt(true),
|
||||
SetDebug(true),
|
||||
SetDebug(false),
|
||||
SetUnpublished(true),
|
||||
SetReduceIdle(true),
|
||||
SetReduceIdleTime(300001),
|
||||
@ -142,13 +141,13 @@ func TestOptionHost(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
|
||||
func TestOptionPortInt(t *testing.T) {
|
||||
@ -164,7 +163,7 @@ func TestOptionPortInt(t *testing.T) {
|
||||
SetInBackups(2),
|
||||
SetOutBackups(2),
|
||||
SetEncrypt(true),
|
||||
SetDebug(true),
|
||||
SetDebug(false),
|
||||
SetUnpublished(true),
|
||||
SetReduceIdle(true),
|
||||
SetReduceIdleTime(300001),
|
||||
@ -180,12 +179,11 @@ func TestOptionPortInt(t *testing.T) {
|
||||
} else {
|
||||
t.Log(result)
|
||||
}
|
||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
||||
_, err = client.CreateStreamSession("")
|
||||
if err := client.Close(); err != nil {
|
||||
t.Fatalf("client.Close() Error: %q\n", err)
|
||||
}
|
||||
fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())
|
||||
/* fmt.Printf("\t destination- %s \n", dest)
|
||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||
}
|
||||
*/
|
||||
|
@ -44,6 +44,25 @@ func parseReply(line string) (*Reply, error) {
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("Malformed Reply.\n%s\n", line)
|
||||
}
|
||||
preParseReply := func() []string {
|
||||
val := ""
|
||||
quote := false
|
||||
for _, v := range parts {
|
||||
if strings.Contains(v, "=\"") {
|
||||
quote = true
|
||||
}
|
||||
if strings.Contains(v, "\"\n") || strings.Contains(v, "\" ") {
|
||||
quote = false
|
||||
}
|
||||
if quote {
|
||||
val += v + "_"
|
||||
} else {
|
||||
val += v + " "
|
||||
}
|
||||
}
|
||||
return strings.Split(strings.TrimSuffix(strings.TrimSpace(val), "_"), " ")
|
||||
}
|
||||
parts = preParseReply()
|
||||
|
||||
r := &Reply{
|
||||
Topic: parts[0],
|
||||
@ -64,7 +83,7 @@ func parseReply(line string) (*Reply, error) {
|
||||
kvPair := strings.SplitN(v, "=", 2)
|
||||
if kvPair != nil {
|
||||
if len(kvPair) != 2 {
|
||||
return nil, fmt.Errorf("Malformed key-value-pair.\n%s\n", kvPair)
|
||||
return nil, fmt.Errorf("Malformed key-value-pair len != 2.\n%s\n", kvPair)
|
||||
}
|
||||
}
|
||||
r.Pairs[kvPair[0]] = kvPair[len(kvPair)-1]
|
||||
|
37
samsocks/main.go
Normal file
37
samsocks/main.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/eyedeekay/goSam"
|
||||
"github.com/getlantern/go-socks5"
|
||||
"log"
|
||||
)
|
||||
|
||||
var (
|
||||
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||
)
|
||||
|
||||
func main() {
|
||||
sam, err := goSam.NewClient(*samaddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Println("Client Created")
|
||||
|
||||
// create a transport that uses SAM to dial TCP Connections
|
||||
conf := &socks5.Config{
|
||||
Dial: sam.DialContext,
|
||||
Resolver: sam,
|
||||
}
|
||||
server, err := socks5.New(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create SOCKS5 proxy on localhost port 8000
|
||||
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
32
sessions.go
32
sessions.go
@ -11,16 +11,18 @@ func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// CreateStreamSession creates a new STREAM Session.
|
||||
// Returns the Id for the new Client.
|
||||
func (c *Client) CreateStreamSession(id int32, dest string) (string, error) {
|
||||
// CreateSession creates a new Session of type style, with an optional destination.
|
||||
// an empty destination is interpreted as "TRANSIENT"
|
||||
// Returns the destination for the new Client or an error.
|
||||
func (c *Client) CreateSession(style, dest string) (string, error) {
|
||||
if dest == "" {
|
||||
dest = "TRANSIENT"
|
||||
}
|
||||
c.id = id
|
||||
// c.id = id
|
||||
r, err := c.sendCmd(
|
||||
"SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s %s %s %s \n",
|
||||
c.id,
|
||||
"SESSION CREATE STYLE=%s ID=%s DESTINATION=%s %s %s %s %s \n",
|
||||
style,
|
||||
c.ID(),
|
||||
dest,
|
||||
c.from(),
|
||||
c.to(),
|
||||
@ -43,3 +45,21 @@ func (c *Client) CreateStreamSession(id int32, dest string) (string, error) {
|
||||
c.destination = r.Pairs["DESTINATION"]
|
||||
return c.destination, nil
|
||||
}
|
||||
|
||||
// CreateStreamSession creates a new STREAM Session.
|
||||
// Returns the Id for the new Client.
|
||||
func (c *Client) CreateStreamSession(dest string) (string, error) {
|
||||
return c.CreateSession("STREAM", dest)
|
||||
}
|
||||
|
||||
// CreateDatagramSession creates a new DATAGRAM Session.
|
||||
// Returns the Id for the new Client.
|
||||
func (c *Client) CreateDatagramSession(dest string) (string, error) {
|
||||
return c.CreateSession("DATAGRAM", dest)
|
||||
}
|
||||
|
||||
// CreateRawSession creates a new RAW Session.
|
||||
// Returns the Id for the new Client.
|
||||
func (c *Client) CreateRawSession(dest string) (string, error) {
|
||||
return c.CreateSession("RAW", dest)
|
||||
}
|
||||
|
15
showhider.css
Normal file
15
showhider.css
Normal file
@ -0,0 +1,15 @@
|
||||
/* edgar showhider CSS file */
|
||||
#show {display:none; }
|
||||
#hide {display:block; }
|
||||
#show:target {display: block; }
|
||||
#hide:target {display: none; }
|
||||
|
||||
#shownav {display:none; }
|
||||
#hidenav {display:block; }
|
||||
#shownav:target {display: block; }
|
||||
#hidenav:target {display: none; }
|
||||
|
||||
#donate {display:none; }
|
||||
#hidedonate {display:block; }
|
||||
#donate:target {display: block; }
|
||||
#hidedonate:target {display: none; }
|
11
stream.go
11
stream.go
@ -5,8 +5,11 @@ import (
|
||||
)
|
||||
|
||||
// StreamConnect asks SAM for a TCP-Like connection to dest, has to be called on a new Client
|
||||
func (c *Client) StreamConnect(id int32, dest string) error {
|
||||
r, err := c.sendCmd("STREAM CONNECT ID=%d DESTINATION=%s %s %s\n", id, dest, c.from(), c.to())
|
||||
func (c *Client) StreamConnect(dest string) error {
|
||||
if dest == "" {
|
||||
return nil
|
||||
}
|
||||
r, err := c.sendCmd("STREAM CONNECT ID=%s DESTINATION=%s %s %s\n", c.ID(), dest, c.from(), c.to())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -25,8 +28,8 @@ func (c *Client) StreamConnect(id int32, dest string) error {
|
||||
}
|
||||
|
||||
// StreamAccept asks SAM to accept a TCP-Like connection
|
||||
func (c *Client) StreamAccept(id int32) (*Reply, error) {
|
||||
r, err := c.sendCmd("STREAM ACCEPT ID=%d SILENT=false\n", id)
|
||||
func (c *Client) StreamAccept() (*Reply, error) {
|
||||
r, err := c.sendCmd("STREAM ACCEPT ID=%s SILENT=false\n", c.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
165
style.css
Normal file
165
style.css
Normal file
@ -0,0 +1,165 @@
|
||||
/* edgar default CSS file */
|
||||
|
||||
body {
|
||||
font-family: "Roboto";
|
||||
font-family: monospace;
|
||||
text-align: justify;
|
||||
background-color: #373636;
|
||||
color: whitesmoke;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
ul {
|
||||
width: 55%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ol {
|
||||
width: 55%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 1%;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 90%;
|
||||
margin-top: 1%;
|
||||
margin-left: 3%;
|
||||
margin-right: 3%;
|
||||
}
|
||||
|
||||
img {
|
||||
float: left;
|
||||
top: 5%;
|
||||
left: 5%;
|
||||
max-width: 60%;
|
||||
display: inline;
|
||||
padding-right: 2%;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.link-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.link-button:active {
|
||||
color: red;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
border-radius: 5%;
|
||||
padding: 1%;
|
||||
border-color: darkgray;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #C6D9FE;
|
||||
padding: 1%;
|
||||
}
|
||||
|
||||
ul li {
|
||||
color: #C6D9FE;
|
||||
}
|
||||
|
||||
iframe {
|
||||
background: aliceblue;
|
||||
border-radius: 15%;
|
||||
margin: 2%;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 36vw;
|
||||
height: 64vh;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.editor-toolbar a {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
color: whitesmoke !important;
|
||||
}
|
||||
|
||||
#feed {
|
||||
width: 60vw;
|
||||
height: unset !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: right;
|
||||
background-color: #373636;
|
||||
color: whitesmoke;
|
||||
border: #C6D9FE solid 1px;
|
||||
}
|
||||
|
||||
.thread-post,
|
||||
.thread {
|
||||
color: whitesmoke !important;
|
||||
background-color: #373636;
|
||||
border: 1px solid darkgray;
|
||||
font-size: inherit;
|
||||
padding-top: 1%;
|
||||
padding-bottom: 1%;
|
||||
}
|
||||
|
||||
.thread-post {
|
||||
margin-left: 4%;
|
||||
}
|
||||
|
||||
input {
|
||||
text-align: center;
|
||||
color: whitesmoke !important;
|
||||
background-color: #373636;
|
||||
border: 1px solid darkgray;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-size: inherit;
|
||||
padding-top: 1%;
|
||||
padding-bottom: 1%;
|
||||
}
|
||||
|
||||
.thread-hash {
|
||||
text-align: right;
|
||||
color: whitesmoke !important;
|
||||
background-color: #373636;
|
||||
border: 1px solid darkgray;
|
||||
font-size: inherit;
|
||||
padding-top: 1%;
|
||||
padding-bottom: 1%;
|
||||
}
|
||||
|
||||
.post-body {
|
||||
text-align: left;
|
||||
color: whitesmoke !important;
|
||||
font-size: inherit;
|
||||
padding-top: 1%;
|
||||
padding-bottom: 1%;
|
||||
}
|
||||
#show {display:none; }
|
||||
#hide {display:block; }
|
||||
#show:target {display: block; }
|
||||
#hide:target {display: none; }
|
||||
|
||||
#shownav {display:none; }
|
||||
#hidenav {display:block; }
|
||||
#shownav:target {display: block; }
|
||||
#hidenav:target {display: none; }
|
||||
|
||||
#navbar {
|
||||
float: right;
|
||||
width: 15%;
|
||||
}
|
||||
#returnhome {
|
||||
font-size: xxx-large;
|
||||
display: inline;
|
||||
}
|
||||
h1 {
|
||||
display: inline;
|
||||
}
|
Reference in New Issue
Block a user