mirror of
https://github.com/go-i2p/onramp.git
synced 2025-08-19 16:45:25 -04:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
48e87d68a9 | ||
![]() |
3f93dec9db | ||
![]() |
daeaa91183 | ||
![]() |
ed7e6f56ae | ||
![]() |
982a496406 | ||
![]() |
d7abd8af30 | ||
![]() |
0d05b3c3f7 | ||
![]() |
00aafc2ede | ||
![]() |
8920b7c847 | ||
![]() |
2791849c67 | ||
![]() |
0d9a9ee10a | ||
![]() |
867026628f | ||
![]() |
56eed1e88f | ||
![]() |
c4e23394dc | ||
![]() |
f9fc572938 | ||
![]() |
e184eda3c1 | ||
![]() |
a0a35dd81c | ||
![]() |
7ef5793e5a | ||
![]() |
c2b8660d5e | ||
![]() |
680d5c000b | ||
![]() |
c2b56d35e2 | ||
![]() |
2a53e8347c | ||
![]() |
dcb997a327 | ||
![]() |
d6a5a60d6f | ||
![]() |
c60c135814 | ||
![]() |
8f08410320 | ||
![]() |
cdad2747a7 | ||
![]() |
394c9f9fb8 | ||
![]() |
f32a695cff | ||
![]() |
41dcb29429 | ||
![]() |
0e2d9a60a4 | ||
![]() |
f654f2635b | ||
![]() |
eb11a4ec64 | ||
![]() |
e2e443e158 | ||
![]() |
c93b68c0ab | ||
![]() |
af628a80ce | ||
![]() |
c6b30ad4cb | ||
![]() |
002fd2f79c | ||
![]() |
2f2d359ffb | ||
![]() |
59c4ed7e73 | ||
![]() |
dc495c94f6 | ||
![]() |
64cb1842d0 | ||
![]() |
55f43b8382 | ||
![]() |
1c866297b5 | ||
![]() |
8170ddbce2 | ||
![]() |
cd87569359 | ||
![]() |
b0d86c9654 | ||
![]() |
d7f20533be | ||
![]() |
3f39d265f7 | ||
![]() |
962259e26c | ||
![]() |
1ccf3ab24b |
20
.github/workflows/auto-assign.yml
vendored
Normal file
20
.github/workflows/auto-assign.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Auto Assign
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request:
|
||||
types: [opened]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: 'Auto-assign issue'
|
||||
uses: pozil/auto-assign-issue@v1
|
||||
with:
|
||||
repo-token:${{ secrets.GITHUB_TOKEN }}
|
||||
assignees: eyedeekay
|
||||
numOfAssignee: 1
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -14,3 +14,6 @@
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
data-dir*
|
||||
i2pkeys/
|
||||
onionkeys/
|
||||
tlskeys/
|
18
DESC.html
18
DESC.html
@@ -7,6 +7,7 @@
|
||||
<meta name="description" content="onramp.git" />
|
||||
<meta name="keywords" content="main" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
@@ -16,6 +17,11 @@
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
@@ -45,11 +51,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1>
|
||||
<a href="#onramp" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
onramp
|
||||
</h1>
|
||||
<p>
|
||||
An above-all easy to use library for setting up Tor and I2P services and clients.
|
||||
</p>
|
||||
<div id="sourcecode">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/onramp.git">
|
||||
Source Code: (https://github.com/eyedeekay/onramp.git)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
|
185
DOCS.html
185
DOCS.html
@@ -7,6 +7,7 @@
|
||||
<meta name="description" content="onramp.git" />
|
||||
<meta name="keywords" content="main" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
@@ -16,6 +17,11 @@
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
@@ -45,45 +51,65 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1>
|
||||
<a href="#onramp-i2p-and-tor-library" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Onramp I2P and Tor Library
|
||||
</h1>
|
||||
<p>
|
||||
<a href="http://pkg.go.dev/." rel="nofollow">
|
||||
<img src="https://img.shields.io/badge/pkg.go.dev-doc-blue" alt="GoDoc"/>
|
||||
<img src="https://img.shields.io/badge/pkg.go.dev-doc-blue" alt="GoDoc">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/." rel="nofollow">
|
||||
<img src="https://goreportcard.com/badge/." alt="Go Report Card"/>
|
||||
<img src="https://goreportcard.com/badge/." alt="Go Report Card">
|
||||
</a>
|
||||
</p>
|
||||
<h2>
|
||||
<a href="#variables" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Variables
|
||||
</h2>
|
||||
<p>
|
||||
I2P_KEYSTORE_PATH is the place where I2P Keys will be saved.
|
||||
it defaults to the directory “i2pkeys” current working directory
|
||||
it defaults to the directory "i2pkeys" current working directory
|
||||
reference it by calling I2PKeystorePath() to check for errors
|
||||
</p>
|
||||
<pre><code>var I2P_KEYSTORE_PATH = i2pdefault
|
||||
</code></pre>
|
||||
<div>
|
||||
<pre>var I2P_KEYSTORE_PATH = i2pdefault
|
||||
</pre>
|
||||
</div>
|
||||
<p>
|
||||
ONION_KEYSTORE_PATH is the place where Onion Keys will be saved.
|
||||
it defaults to the directory “onionkeys” current working directory
|
||||
it defaults to the directory "onionkeys" current working directory
|
||||
reference it by calling OnionKeystorePath() to check for errors
|
||||
</p>
|
||||
<pre><code>var ONION_KEYSTORE_PATH = tordefault
|
||||
</code></pre>
|
||||
<pre><code>var OPT_DEFAULTS = sam3.Options_Default
|
||||
</code></pre>
|
||||
<div>
|
||||
<pre>var ONION_KEYSTORE_PATH = tordefault
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<pre>var OPT_DEFAULTS = sam3.Options_Default
|
||||
</pre>
|
||||
</div>
|
||||
<p>
|
||||
SAM_ADDR is the default I2P SAM address. It can be overridden by the
|
||||
struct or by changing this variable.
|
||||
</p>
|
||||
<pre><code>var SAM_ADDR = "127.0.0.1:7656"
|
||||
</code></pre>
|
||||
<div>
|
||||
<pre>var SAM_ADDR = "127.0.0.1:7656"
|
||||
</pre>
|
||||
</div>
|
||||
<h2>
|
||||
<a href="#functions" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Functions
|
||||
</h2>
|
||||
<h3>
|
||||
<a href="#func-closeallgarlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L211" rel="nofollow">
|
||||
CloseAllGarlic
|
||||
@@ -99,6 +125,9 @@
|
||||
affect objects instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-closeallonion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L174" rel="nofollow">
|
||||
CloseAllOnion
|
||||
@@ -114,6 +143,9 @@
|
||||
affect objects instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-closegarlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L220" rel="nofollow">
|
||||
CloseGarlic
|
||||
@@ -129,6 +161,9 @@
|
||||
objects instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-closeonion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L183" rel="nofollow">
|
||||
CloseOnion
|
||||
@@ -144,6 +179,9 @@
|
||||
objects instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-createtlscertificate" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/tls.go#L20" rel="nofollow">
|
||||
CreateTLSCertificate
|
||||
@@ -155,6 +193,9 @@
|
||||
</code>
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-deletegarlickeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L159" rel="nofollow">
|
||||
DeleteGarlicKeys
|
||||
@@ -172,6 +213,9 @@
|
||||
address.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-deletei2pkeystore" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L60" rel="nofollow">
|
||||
DeleteI2PKeyStore
|
||||
@@ -186,6 +230,9 @@
|
||||
DeleteI2PKeyStore deletes the I2P Keystore.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-deleteonionkeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L216" rel="nofollow">
|
||||
DeleteOnionKeys
|
||||
@@ -201,6 +248,9 @@
|
||||
keystore + tunName.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-deletetorkeystore" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L78" rel="nofollow">
|
||||
DeleteTorKeyStore
|
||||
@@ -215,6 +265,9 @@
|
||||
DeleteTorKeyStore deletes the Onion Keystore.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-dial" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L85" rel="nofollow">
|
||||
Dial
|
||||
@@ -231,6 +284,9 @@
|
||||
if the address ends in anything else, it returns a Tor connection.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-dialgarlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L246" rel="nofollow">
|
||||
DialGarlic
|
||||
@@ -242,11 +298,14 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
DialGarlic returns a net.Conn for a garlic structure’s keys
|
||||
DialGarlic returns a net.Conn for a garlic structure's keys
|
||||
corresponding to a structure managed by the onramp library
|
||||
and not instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-dialonion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L205" rel="nofollow">
|
||||
DialOnion
|
||||
@@ -258,11 +317,14 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
DialOnion returns a net.Conn for a onion structure’s keys
|
||||
DialOnion returns a net.Conn for a onion structure's keys
|
||||
corresponding to a structure managed by the onramp library
|
||||
and not instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-getjoinedwd" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L17" rel="nofollow">
|
||||
GetJoinedWD
|
||||
@@ -277,6 +339,9 @@
|
||||
GetJoinedWD returns the working directory joined with the given path.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-i2pkeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L173" rel="nofollow">
|
||||
I2PKeys
|
||||
@@ -292,6 +357,9 @@
|
||||
tunnel name. If none exist, they are created and stored.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-i2pkeystorepath" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L49" rel="nofollow">
|
||||
I2PKeystorePath
|
||||
@@ -308,6 +376,9 @@
|
||||
not exist, it creates it.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-listen" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L101" rel="nofollow">
|
||||
Listen
|
||||
@@ -322,9 +393,12 @@
|
||||
Listen returns a listener for the given network and address.
|
||||
if network is i2p or garlic, it returns an I2P listener.
|
||||
if network is tor or onion, it returns an Onion listener.
|
||||
if keys ends with “.i2p”, it returns an I2P listener.
|
||||
if keys ends with ".i2p", it returns an I2P listener.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-listengarlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L234" rel="nofollow">
|
||||
ListenGarlic
|
||||
@@ -336,11 +410,14 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
ListenGarlic returns a net.Listener for a garlic structure’s keys
|
||||
ListenGarlic returns a net.Listener for a garlic structure's keys
|
||||
corresponding to a structure managed by the onramp library
|
||||
and not instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-listenonion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L193" rel="nofollow">
|
||||
ListenOnion
|
||||
@@ -352,11 +429,14 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
ListenOnion returns a net.Listener for a onion structure’s keys
|
||||
ListenOnion returns a net.Listener for a onion structure's keys
|
||||
corresponding to a structure managed by the onramp library
|
||||
and not instantiated by an app.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-newtlscertificate" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/tls.go#L114" rel="nofollow">
|
||||
NewTLSCertificate
|
||||
@@ -368,6 +448,9 @@
|
||||
</code>
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-newtlscertificatealtnames" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/tls.go#L118" rel="nofollow">
|
||||
NewTLSCertificateAltNames
|
||||
@@ -379,6 +462,9 @@
|
||||
</code>
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-torkeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L135" rel="nofollow">
|
||||
TorKeys
|
||||
@@ -395,6 +481,9 @@
|
||||
returned. If it does not exist, it will be generated.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#func-torkeystorepath" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/common.go#L67" rel="nofollow">
|
||||
TorKeystorePath
|
||||
@@ -411,9 +500,15 @@
|
||||
not exist, it creates it.
|
||||
</p>
|
||||
<h2>
|
||||
<a href="#types" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Types
|
||||
</h2>
|
||||
<h3>
|
||||
<a href="#type-garlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
type
|
||||
<a href="/garlic.go#L19" rel="nofollow">
|
||||
Garlic
|
||||
@@ -429,6 +524,9 @@
|
||||
has a valid I2PKeys and StreamSession.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-newgarlic" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/garlic.go#L140" rel="nofollow">
|
||||
NewGarlic
|
||||
@@ -444,6 +542,9 @@
|
||||
I2P streaming.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-garlic-close" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Garlic)
|
||||
<a href="/garlic.go#L111" rel="nofollow">
|
||||
Close
|
||||
@@ -455,9 +556,12 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Close closes the Garlic structure’s sessions and listeners.
|
||||
Close closes the Garlic structure's sessions and listeners.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-garlic-deletekeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Garlic)
|
||||
<a href="/garlic.go#L134" rel="nofollow">
|
||||
DeleteKeys
|
||||
@@ -469,6 +573,9 @@
|
||||
</code>
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-garlic-dial" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Garlic)
|
||||
<a href="/garlic.go#L99" rel="nofollow">
|
||||
Dial
|
||||
@@ -480,9 +587,12 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Dial returns a net.Conn for the Garlic structure’s I2P keys.
|
||||
Dial returns a net.Conn for the Garlic structure's I2P keys.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-garlic-keys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Garlic)
|
||||
<a href="/garlic.go#L126" rel="nofollow">
|
||||
Keys
|
||||
@@ -498,6 +608,9 @@
|
||||
exist, they are created and stored.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-garlic-listen" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Garlic)
|
||||
<a href="/garlic.go#L81" rel="nofollow">
|
||||
Listen
|
||||
@@ -509,9 +622,12 @@
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Listen returns a net.Listener for the Garlic structure’s I2P keys.
|
||||
Listen returns a net.Listener for the Garlic structure's I2P keys.
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#type-onion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
type
|
||||
<a href="/onion.go#L24" rel="nofollow">
|
||||
Onion
|
||||
@@ -528,6 +644,9 @@
|
||||
keys.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-newonion" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func
|
||||
<a href="/onion.go#L126" rel="nofollow">
|
||||
NewOnion
|
||||
@@ -542,6 +661,9 @@
|
||||
NewOnion returns a new Onion object.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-onion-close" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Onion)
|
||||
<a href="/onion.go#L109" rel="nofollow">
|
||||
Close
|
||||
@@ -556,6 +678,9 @@
|
||||
Close closes the Onion Service and all associated resources.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-onion-deletekeys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Onion)
|
||||
<a href="/onion.go#L121" rel="nofollow">
|
||||
DeleteKeys
|
||||
@@ -572,6 +697,9 @@
|
||||
address.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-onion-dial" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Onion)
|
||||
<a href="/onion.go#L104" rel="nofollow">
|
||||
Dial
|
||||
@@ -586,6 +714,9 @@
|
||||
Dial returns a net.Conn to the given onion address or clearnet address.
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-onion-keys" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Onion)
|
||||
<a href="/onion.go#L114" rel="nofollow">
|
||||
Keys
|
||||
@@ -600,6 +731,9 @@
|
||||
Keys returns the keys for the Onion
|
||||
</p>
|
||||
<h4>
|
||||
<a href="#func-onion-listen" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
func (*Onion)
|
||||
<a href="/onion.go#L99" rel="nofollow">
|
||||
Listen
|
||||
@@ -614,13 +748,22 @@
|
||||
ListenOnion returns a net.Listener which will listen on an onion
|
||||
address, and will automatically generate a keypair and store it.
|
||||
</p>
|
||||
<hr/>
|
||||
<hr>
|
||||
<p>
|
||||
Readme created from Go doc with
|
||||
<a href="https://github.com/posener/goreadme" rel="nofollow">
|
||||
goreadme
|
||||
</a>
|
||||
</p>
|
||||
<div id="sourcecode">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/onramp.git">
|
||||
Source Code: (https://github.com/eyedeekay/onramp.git)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
|
351
EXAMPLE.html
351
EXAMPLE.html
@@ -7,6 +7,7 @@
|
||||
<meta name="description" content="onramp.git" />
|
||||
<meta name="keywords" content="main" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
@@ -16,6 +17,11 @@
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
@@ -45,195 +51,232 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1>
|
||||
<a href="#example-usage" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Example Usage
|
||||
</h1>
|
||||
<h3>
|
||||
<a href="#usage-as-instance-of-a-struct-listener" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage as instance of a struct, Listener
|
||||
</h3>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"fmt"</span>
|
||||
<span>"log"</span>
|
||||
<span>"net/http"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
garlic := &onramp.Garlic{}
|
||||
defer garlic.Close()
|
||||
listener, err := garlic.Listen()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %q", r.URL.Path)
|
||||
})
|
||||
if err := http.Serve(listener, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>garlic</span> <span>:=</span> <span>&</span><span>onramp</span><span>.</span><span>Garlic</span><span>{</span><span>}</span>
|
||||
<span>defer</span> <span>garlic</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>listener</span><span>,</span> <span>err</span> <span>:=</span> <span>garlic</span><span>.</span><span>Listen</span><span>(</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>listener</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>http</span><span>.</span><span>HandleFunc</span><span>(</span><span>"/"</span><span>,</span> <span>func</span><span>(</span><span>w</span> <span>http</span><span>.</span><span>ResponseWriter</span><span>,</span> <span>r</span> <span>*</span><span>http</span><span>.</span><span>Request</span><span>)</span> <span>{</span>
|
||||
<span>fmt</span><span>.</span><span>Fprintf</span><span>(</span><span>w</span><span>,</span> <span>"Hello, %q"</span><span>,</span> <span>r</span><span>.</span><span>URL</span><span>.</span><span>Path</span><span>)</span>
|
||||
<span>}</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>:=</span> <span>http</span><span>.</span><span>Serve</span><span>(</span><span>listener</span><span>,</span> <span>nil</span><span>)</span><span>;</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<h3>
|
||||
<a href="#usage-as-instance-of-a-struct-dialer" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage as instance of a struct, Dialer
|
||||
</h3>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"fmt"</span>
|
||||
<span>"io/ioutil"</span>
|
||||
<span>"log"</span>
|
||||
<span>"net/http"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
garlic := &onramp.Garlic{}
|
||||
defer garlic.Close()
|
||||
transport := http.Transport{
|
||||
Dial: garlic.Dial,
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: &transport,
|
||||
}
|
||||
resp, err := client.Get("http://" + listener.Addr().String() + "/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
fmt.Println(resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>garlic</span> <span>:=</span> <span>&</span><span>onramp</span><span>.</span><span>Garlic</span><span>{</span><span>}</span>
|
||||
<span>defer</span> <span>garlic</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>transport</span> <span>:=</span> <span>http</span><span>.</span><span>Transport</span><span>{</span>
|
||||
<span>Dial</span><span>:</span> <span>garlic</span><span>.</span><span>Dial</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>client</span> <span>:=</span> <span>&</span><span>http</span><span>.</span><span>Client</span><span>{</span>
|
||||
<span>Transport</span><span>:</span> <span>&</span><span>transport</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>resp</span><span>,</span> <span>err</span> <span>:=</span> <span>client</span><span>.</span><span>Get</span><span>(</span><span>"http://"</span> <span>+</span> <span>listener</span><span>.</span><span>Addr</span><span>(</span><span>)</span><span>.</span><span>String</span><span>(</span><span>)</span> <span>+</span> <span>"/"</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>resp</span><span>.</span><span>Body</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>resp</span><span>.</span><span>Status</span><span>)</span>
|
||||
<span>body</span><span>,</span> <span>err</span> <span>:=</span> <span>ioutil</span><span>.</span><span>ReadAll</span><span>(</span><span>resp</span><span>.</span><span>Body</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>string</span><span>(</span><span>body</span><span>)</span><span>)</span>
|
||||
<span>}</span>
|
||||
|
||||
</code></pre>
|
||||
</pre>
|
||||
</div>
|
||||
<h3>
|
||||
<a href="#usage-as-instance-of-a-struct-listener-and-dialer-on-same-address" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage as instance of a struct, Listener and Dialer on same address
|
||||
</h3>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"fmt"</span>
|
||||
<span>"io/ioutil"</span>
|
||||
<span>"log"</span>
|
||||
<span>"net"</span>
|
||||
<span>"net/http"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
garlic := &Garlic{}
|
||||
defer garlic.Close()
|
||||
listener, err := garlic.Listen()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("listener:", listener.Addr().String())
|
||||
defer listener.Close()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %q", r.URL.Path)
|
||||
})
|
||||
go Serve(listener)
|
||||
transport := http.Transport{
|
||||
Dial: garlic.Dial,
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: &transport,
|
||||
}
|
||||
resp, err := client.Get("http://" + listener.Addr().String() + "/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
fmt.Println(resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>garlic</span> <span>:=</span> <span>&</span><span>Garlic</span><span>{</span><span>}</span>
|
||||
<span>defer</span> <span>garlic</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>listener</span><span>,</span> <span>err</span> <span>:=</span> <span>garlic</span><span>.</span><span>Listen</span><span>(</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>log</span><span>.</span><span>Println</span><span>(</span><span>"listener:"</span><span>,</span> <span>listener</span><span>.</span><span>Addr</span><span>(</span><span>)</span><span>.</span><span>String</span><span>(</span><span>)</span><span>)</span>
|
||||
<span>defer</span> <span>listener</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>http</span><span>.</span><span>HandleFunc</span><span>(</span><span>"/"</span><span>,</span> <span>func</span><span>(</span><span>w</span> <span>http</span><span>.</span><span>ResponseWriter</span><span>,</span> <span>r</span> <span>*</span><span>http</span><span>.</span><span>Request</span><span>)</span> <span>{</span>
|
||||
<span>fmt</span><span>.</span><span>Fprintf</span><span>(</span><span>w</span><span>,</span> <span>"Hello, %q"</span><span>,</span> <span>r</span><span>.</span><span>URL</span><span>.</span><span>Path</span><span>)</span>
|
||||
<span>}</span><span>)</span>
|
||||
<span>go</span> <span>Serve</span><span>(</span><span>listener</span><span>)</span>
|
||||
<span>transport</span> <span>:=</span> <span>http</span><span>.</span><span>Transport</span><span>{</span>
|
||||
<span>Dial</span><span>:</span> <span>garlic</span><span>.</span><span>Dial</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>client</span> <span>:=</span> <span>&</span><span>http</span><span>.</span><span>Client</span><span>{</span>
|
||||
<span>Transport</span><span>:</span> <span>&</span><span>transport</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>resp</span><span>,</span> <span>err</span> <span>:=</span> <span>client</span><span>.</span><span>Get</span><span>(</span><span>"http://"</span> <span>+</span> <span>listener</span><span>.</span><span>Addr</span><span>(</span><span>)</span><span>.</span><span>String</span><span>(</span><span>)</span> <span>+</span> <span>"/"</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>resp</span><span>.</span><span>Body</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>resp</span><span>.</span><span>Status</span><span>)</span>
|
||||
<span>body</span><span>,</span> <span>err</span> <span>:=</span> <span>ioutil</span><span>.</span><span>ReadAll</span><span>(</span><span>resp</span><span>.</span><span>Body</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>string</span><span>(</span><span>body</span><span>)</span><span>)</span>
|
||||
<span>}</span>
|
||||
|
||||
func Serve(listener net.Listener) {
|
||||
if err := http.Serve(listener, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<span>func</span> <span>Serve</span><span>(</span><span>listener</span> <span>net</span><span>.</span><span>Listener</span><span>)</span> <span>{</span>
|
||||
<span>if</span> <span>err</span> <span>:=</span> <span>http</span><span>.</span><span>Serve</span><span>(</span><span>listener</span><span>,</span> <span>nil</span><span>)</span><span>;</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<h3>
|
||||
<a href="#usage-as-automatically-managed-listeners" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage as automatically-managed Listeners
|
||||
</h3>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"fmt"</span>
|
||||
<span>"log"</span>
|
||||
<span>"net/http"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
defer onramp.CloseAll()
|
||||
listener, err := onramp.Listen("tcp", "service.i2p")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %q", r.URL.Path)
|
||||
})
|
||||
if err := http.Serve(listener, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>defer</span> <span>onramp</span><span>.</span><span>CloseAll</span><span>(</span><span>)</span>
|
||||
<span>listener</span><span>,</span> <span>err</span> <span>:=</span> <span>onramp</span><span>.</span><span>Listen</span><span>(</span><span>"tcp"</span><span>,</span> <span>"service.i2p"</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>listener</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>http</span><span>.</span><span>HandleFunc</span><span>(</span><span>"/"</span><span>,</span> <span>func</span><span>(</span><span>w</span> <span>http</span><span>.</span><span>ResponseWriter</span><span>,</span> <span>r</span> <span>*</span><span>http</span><span>.</span><span>Request</span><span>)</span> <span>{</span>
|
||||
<span>fmt</span><span>.</span><span>Fprintf</span><span>(</span><span>w</span><span>,</span> <span>"Hello, %q"</span><span>,</span> <span>r</span><span>.</span><span>URL</span><span>.</span><span>Path</span><span>)</span>
|
||||
<span>}</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>:=</span> <span>http</span><span>.</span><span>Serve</span><span>(</span><span>listener</span><span>,</span> <span>nil</span><span>)</span><span>;</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>}</span>
|
||||
|
||||
</code></pre>
|
||||
</pre>
|
||||
</div>
|
||||
<h3>
|
||||
<a href="#usage-as-automatically-managed-dialers" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage as automatically-managed Dialers
|
||||
</h3>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"fmt"</span>
|
||||
<span>"io/ioutil"</span>
|
||||
<span>"log"</span>
|
||||
<span>"net/http"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
defer onramp.CloseAll()
|
||||
transport := http.Transport{
|
||||
Dial: onramp.Dial,
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: &transport,
|
||||
}
|
||||
resp, err := client.Get("http://" + listener.Addr().String() + "/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
fmt.Println(resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>defer</span> <span>onramp</span><span>.</span><span>CloseAll</span><span>(</span><span>)</span>
|
||||
<span>transport</span> <span>:=</span> <span>http</span><span>.</span><span>Transport</span><span>{</span>
|
||||
<span>Dial</span><span>:</span> <span>onramp</span><span>.</span><span>Dial</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>client</span> <span>:=</span> <span>&</span><span>http</span><span>.</span><span>Client</span><span>{</span>
|
||||
<span>Transport</span><span>:</span> <span>&</span><span>transport</span><span>,</span>
|
||||
<span>}</span>
|
||||
<span>resp</span><span>,</span> <span>err</span> <span>:=</span> <span>client</span><span>.</span><span>Get</span><span>(</span><span>"http://"</span> <span>+</span> <span>listener</span><span>.</span><span>Addr</span><span>(</span><span>)</span><span>.</span><span>String</span><span>(</span><span>)</span> <span>+</span> <span>"/"</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>resp</span><span>.</span><span>Body</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>resp</span><span>.</span><span>Status</span><span>)</span>
|
||||
<span>body</span><span>,</span> <span>err</span> <span>:=</span> <span>ioutil</span><span>.</span><span>ReadAll</span><span>(</span><span>resp</span><span>.</span><span>Body</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>string</span><span>(</span><span>body</span><span>)</span><span>)</span>
|
||||
<span>}</span>
|
||||
|
||||
</code></pre>
|
||||
</pre>
|
||||
</div>
|
||||
<div id="sourcecode">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/onramp.git">
|
||||
Source Code: (https://github.com/eyedeekay/onramp.git)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -44,7 +44,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -135,7 +135,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -167,7 +167,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
28
Makefile
Normal file
28
Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
USER_GH=go-i2p
|
||||
VERSION=0.33.92
|
||||
CREDIT='contributors to this release: @hkh4n, @eyedeekay'
|
||||
packagename=onramp
|
||||
|
||||
echo: fmt
|
||||
@echo "type make version to do release $(VERSION)"
|
||||
|
||||
version:
|
||||
github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION) $(CREDIT)"
|
||||
|
||||
del:
|
||||
github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
||||
|
||||
tar:
|
||||
tar --exclude .git \
|
||||
--exclude .go \
|
||||
--exclude bin \
|
||||
--exclude examples \
|
||||
-cJvf ../$(packagename)_$(VERSION).orig.tar.xz .
|
||||
|
||||
link:
|
||||
rm -f ../goSam
|
||||
ln -sf . ../goSam
|
||||
|
||||
fmt:
|
||||
find . -name '*.go' -exec gofmt -w -s {} \;
|
42
README.md
42
README.md
@@ -1,6 +1,8 @@
|
||||
onramp
|
||||
======
|
||||
|
||||
[](https://goreportcard.com/report/github.com/go-i2p/onramp)
|
||||
|
||||
High-level, easy-to-use listeners and clients for I2P and onion URL's from Go.
|
||||
Provides only the most widely-used functions in a basic way. It expects nothing
|
||||
from the users, an otherwise empty instance of the structs will listen and dial
|
||||
@@ -12,9 +14,11 @@ This means that hidden services will maintain their identities, and that clients
|
||||
will always have the same return addresses. If you don't want this behavior,
|
||||
make sure to delete the "keystore" when your app closes or when your application
|
||||
needs to cycle keys by calling the `Garlic.DeleteKeys()` or `Onion.DeleteKeys()`
|
||||
function. For more information, check out the [godoc](http://pkg.go.dev/github.com/eyedeekay/onramp).
|
||||
function. For more information, check out the [godoc](http://pkg.go.dev/github.com/go-i2p/onramp).
|
||||
|
||||
- **[Source Code](https://github.com/eyedeekay/onramp)**
|
||||
- **[Source Code](https://github.com/go-i2p/onramp)**
|
||||
|
||||
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days.
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -36,7 +40,7 @@ package main
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -62,7 +66,7 @@ package main
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/go-i2p/onramp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -74,4 +78,32 @@ func main() {
|
||||
}
|
||||
defer listener.Close()
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## Verbosity ##
|
||||
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled.
|
||||
|
||||
There are three available log levels:
|
||||
|
||||
- Debug
|
||||
```shell
|
||||
export DEBUG_I2P=debug
|
||||
```
|
||||
- Warn
|
||||
```shell
|
||||
export DEBUG_I2P=warn
|
||||
```
|
||||
- Error
|
||||
```shell
|
||||
export DEBUG_I2P=error
|
||||
```
|
||||
|
||||
If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
|
||||
|
||||
## Contributing
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT license, see LICENSE for more information.
|
||||
|
76
common.go
76
common.go
@@ -9,24 +9,36 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
//go:generate go run -tags gen ./gen.go
|
||||
|
||||
// GetJoinedWD returns the working directory joined with the given path.
|
||||
func GetJoinedWD(dir string) (string, error) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
//log.WithError(err).Error("Failed to get working directory")
|
||||
return "", err
|
||||
}
|
||||
jwd := filepath.Join(wd, dir)
|
||||
ajwd, err := filepath.Abs(jwd)
|
||||
if err != nil {
|
||||
//log.WithError(err).WithField("path", jwd).Error("Failed to get absolute path")
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(ajwd); err != nil {
|
||||
os.MkdirAll(ajwd, 0755)
|
||||
//log.WithField("path", ajwd).Debug("Directory does not exist, creating")
|
||||
if err := os.MkdirAll(ajwd, 0755); err != nil {
|
||||
//log.WithError(err).WithField("path", ajwd).Error("Failed to create directory")
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
//log.WithField("path", ajwd).Debug("Successfully got joined working directory")
|
||||
return ajwd, nil
|
||||
}
|
||||
|
||||
@@ -53,68 +65,112 @@ var TLS_KEYSTORE_PATH = tlsdefault
|
||||
// path is not set, it returns the default path. If the path does
|
||||
// not exist, it creates it.
|
||||
func I2PKeystorePath() (string, error) {
|
||||
log.WithField("path", I2P_KEYSTORE_PATH).Debug("Checking I2P keystore path")
|
||||
if _, err := os.Stat(I2P_KEYSTORE_PATH); err != nil {
|
||||
log.WithField("path", I2P_KEYSTORE_PATH).Debug("I2P keystore directory does not exist, creating")
|
||||
err := os.MkdirAll(I2P_KEYSTORE_PATH, 0755)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", I2P_KEYSTORE_PATH).Error("Failed to create I2P keystore directory")
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
log.WithField("path", I2P_KEYSTORE_PATH).Debug("I2P keystore path verified")
|
||||
return I2P_KEYSTORE_PATH, nil
|
||||
}
|
||||
|
||||
// DeleteI2PKeyStore deletes the I2P Keystore.
|
||||
func DeleteI2PKeyStore() error {
|
||||
return os.RemoveAll(I2P_KEYSTORE_PATH)
|
||||
log.WithField("path", I2P_KEYSTORE_PATH).Debug("Attempting to delete I2P keystore")
|
||||
err := os.RemoveAll(I2P_KEYSTORE_PATH)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", I2P_KEYSTORE_PATH).Error("Failed to delete I2P keystore")
|
||||
return err
|
||||
}
|
||||
log.WithField("path", I2P_KEYSTORE_PATH).Debug("Successfully deleted I2P keystore")
|
||||
return nil
|
||||
//return os.RemoveAll(I2P_KEYSTORE_PATH)
|
||||
}
|
||||
|
||||
// TorKeystorePath returns the path to the Onion Keystore. If the
|
||||
// path is not set, it returns the default path. If the path does
|
||||
// not exist, it creates it.
|
||||
func TorKeystorePath() (string, error) {
|
||||
log.WithField("path", ONION_KEYSTORE_PATH).Debug("Checking Tor keystore path")
|
||||
if _, err := os.Stat(ONION_KEYSTORE_PATH); err != nil {
|
||||
log.WithField("path", ONION_KEYSTORE_PATH).Debug("Tor keystore directory does not exist, creating")
|
||||
err := os.MkdirAll(ONION_KEYSTORE_PATH, 0755)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", ONION_KEYSTORE_PATH).Error("Failed to create Tor keystore directory")
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
log.WithField("path", ONION_KEYSTORE_PATH).Debug("Tor keystore path verified")
|
||||
return ONION_KEYSTORE_PATH, nil
|
||||
}
|
||||
|
||||
// DeleteTorKeyStore deletes the Onion Keystore.
|
||||
func DeleteTorKeyStore() error {
|
||||
return os.RemoveAll(ONION_KEYSTORE_PATH)
|
||||
log.WithField("path", ONION_KEYSTORE_PATH).Debug("Attempting to delete Tor keystore")
|
||||
err := os.RemoveAll(ONION_KEYSTORE_PATH)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", ONION_KEYSTORE_PATH).Error("Failed to delete Tor keystore")
|
||||
return err
|
||||
}
|
||||
log.WithField("path", ONION_KEYSTORE_PATH).Debug("Successfully deleted Tor keystore")
|
||||
return nil
|
||||
//return os.RemoveAll(ONION_KEYSTORE_PATH)
|
||||
}
|
||||
|
||||
// TLSKeystorePath returns the path to the TLS Keystore. If the
|
||||
// path is not set, it returns the default path. If the path does
|
||||
// not exist, it creates it.
|
||||
func TLSKeystorePath() (string, error) {
|
||||
log.WithField("path", TLS_KEYSTORE_PATH).Debug("Checking TLS keystore path")
|
||||
if _, err := os.Stat(TLS_KEYSTORE_PATH); err != nil {
|
||||
log.WithField("path", TLS_KEYSTORE_PATH).Debug("TLS keystore directory does not exist, creating")
|
||||
err := os.MkdirAll(TLS_KEYSTORE_PATH, 0755)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", TLS_KEYSTORE_PATH).Error("Failed to create TLS keystore directory")
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
log.WithField("path", TLS_KEYSTORE_PATH).Debug("TLS keystore path verified")
|
||||
return TLS_KEYSTORE_PATH, nil
|
||||
}
|
||||
|
||||
// DeleteTLSKeyStore deletes the TLS Keystore.
|
||||
func DeleteTLSKeyStore() error {
|
||||
return os.RemoveAll(TLS_KEYSTORE_PATH)
|
||||
log.WithField("path", TLS_KEYSTORE_PATH).Debug("Attempting to delete TLS keystore")
|
||||
err := os.RemoveAll(TLS_KEYSTORE_PATH)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", TLS_KEYSTORE_PATH).Error("Failed to delete TLS keystore")
|
||||
return err
|
||||
}
|
||||
log.WithField("path", TLS_KEYSTORE_PATH).Debug("Successfully deleted TLS keystore")
|
||||
return nil
|
||||
//return os.RemoveAll(TLS_KEYSTORE_PATH)
|
||||
}
|
||||
|
||||
// Dial returns a connection for the given network and address.
|
||||
// network is ignored. If the address ends in i2p, it returns an I2P connection.
|
||||
// if the address ends in anything else, it returns a Tor connection.
|
||||
func Dial(network, addr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": network,
|
||||
"address": addr,
|
||||
}).Debug("Attempting to dial")
|
||||
|
||||
url, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("address", addr).Error("Failed to parse address")
|
||||
return nil, err
|
||||
}
|
||||
hostname := url.Hostname()
|
||||
if strings.HasSuffix(hostname, ".i2p") {
|
||||
log.WithField("hostname", hostname).Debug("Using I2P connection for .i2p address")
|
||||
return DialGarlic(network, addr)
|
||||
}
|
||||
log.WithField("hostname", hostname).Debug("Using Tor connection for non-i2p address")
|
||||
return DialOnion(network, addr)
|
||||
}
|
||||
|
||||
@@ -123,19 +179,31 @@ func Dial(network, addr string) (net.Conn, error) {
|
||||
// if network is tor or onion, it returns an Onion listener.
|
||||
// if keys ends with ".i2p", it returns an I2P listener.
|
||||
func Listen(network, keys string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": network,
|
||||
"keys": keys,
|
||||
}).Debug("Attempting to create listener")
|
||||
|
||||
if network == "i2p" || network == "garlic" {
|
||||
log.Debug("Creating I2P listener based on network type")
|
||||
return ListenGarlic(network, keys)
|
||||
}
|
||||
if network == "tor" || network == "onion" {
|
||||
log.Debug("Creating Tor listener based on network type")
|
||||
return ListenOnion(network, keys)
|
||||
}
|
||||
|
||||
url, err := url.Parse(keys)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("keys", keys).Error("Failed to parse keys URL")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hostname := url.Hostname()
|
||||
if strings.HasSuffix(hostname, ".i2p") {
|
||||
log.WithField("hostname", hostname).Debug("Creating I2P listener based on .i2p hostname")
|
||||
return ListenGarlic(network, keys)
|
||||
}
|
||||
log.WithField("hostname", hostname).Debug("Creating Tor listener for non-i2p hostname")
|
||||
return ListenOnion(network, keys)
|
||||
}
|
||||
|
410
garlic.go
410
garlic.go
@@ -4,15 +4,17 @@
|
||||
package onramp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/eyedeekay/i2pkeys"
|
||||
"github.com/eyedeekay/sam3"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/go-i2p/sam3"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Garlic is a ready-made I2P streaming manager. Once initialized it always
|
||||
@@ -20,18 +22,65 @@ import (
|
||||
type Garlic struct {
|
||||
*sam3.StreamListener
|
||||
*sam3.StreamSession
|
||||
i2pkeys.I2PKeys
|
||||
*sam3.DatagramSession
|
||||
ServiceKeys *i2pkeys.I2PKeys
|
||||
*sam3.SAM
|
||||
name string
|
||||
addr string
|
||||
opts []string
|
||||
name string
|
||||
addr string
|
||||
opts []string
|
||||
AddrMode int
|
||||
TorrentMode bool
|
||||
}
|
||||
|
||||
var OPT_DEFAULTS = sam3.Options_Default
|
||||
const (
|
||||
DEST_BASE32 = 0
|
||||
DEST_HASH = 1
|
||||
DEST_HASH_BYTES = 2
|
||||
DEST_BASE32_TRUNCATED = 3
|
||||
DEST_BASE64 = 4
|
||||
DEST_BASE64_BYTES = 5
|
||||
)
|
||||
|
||||
func (g *Garlic) Network() string {
|
||||
if g.StreamListener != nil {
|
||||
return "tcp"
|
||||
} else {
|
||||
return "udp"
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Garlic) addrString(addr string) string {
|
||||
if g.TorrentMode {
|
||||
return addr + ".i2p"
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func (g *Garlic) String() string {
|
||||
var r string
|
||||
switch g.AddrMode {
|
||||
case DEST_HASH:
|
||||
r = g.ServiceKeys.Address.DestHash().Hash()
|
||||
case DEST_HASH_BYTES:
|
||||
hash := g.ServiceKeys.Address.DestHash()
|
||||
r = string(hash[:])
|
||||
case DEST_BASE32_TRUNCATED:
|
||||
r = strings.TrimSuffix(g.ServiceKeys.Address.Base32(), ".b32.i2p")
|
||||
case DEST_BASE32:
|
||||
r = g.ServiceKeys.Address.Base32()
|
||||
case DEST_BASE64:
|
||||
r = g.ServiceKeys.Address.Base64()
|
||||
case DEST_BASE64_BYTES:
|
||||
r = string(g.ServiceKeys.Address.Bytes())
|
||||
default:
|
||||
r = g.ServiceKeys.Address.DestHash().Hash()
|
||||
}
|
||||
return g.addrString(r) // r //strings.TrimLeft(strings.TrimRight(r, "\n"), "\n") //strings.TrimSpace(r)
|
||||
}
|
||||
|
||||
func (g *Garlic) getName() string {
|
||||
if g.name == "" {
|
||||
return "onramp"
|
||||
return "onramp-garlic"
|
||||
}
|
||||
return g.name
|
||||
}
|
||||
@@ -52,71 +101,214 @@ func (g *Garlic) getOptions() []string {
|
||||
|
||||
func (g *Garlic) samSession() (*sam3.SAM, error) {
|
||||
if g.SAM == nil {
|
||||
log.WithField("address", g.getAddr()).Debug("Creating new SAM session")
|
||||
var err error
|
||||
g.SAM, err = sam3.NewSAM(g.getAddr())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session")
|
||||
return nil, fmt.Errorf("onramp samSession: %v", err)
|
||||
}
|
||||
log.Debug("SAM session created successfully")
|
||||
}
|
||||
return g.SAM, nil
|
||||
}
|
||||
|
||||
func (g Garlic) setupStreamSession() (*sam3.StreamSession, error) {
|
||||
func (g *Garlic) setupStreamSession() (*sam3.StreamSession, error) {
|
||||
if g.StreamSession == nil {
|
||||
log.WithField("name", g.getName()).Debug("Setting up stream session")
|
||||
var err error
|
||||
g.I2PKeys, err = g.Keys()
|
||||
g.ServiceKeys, err = g.Keys()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keys for stream session")
|
||||
return nil, fmt.Errorf("onramp setupStreamSession: %v", err)
|
||||
}
|
||||
log.Println("Creating stream session with keys:", g.I2PKeys.Address.Base32())
|
||||
g.StreamSession, err = g.SAM.NewStreamSession(g.getName(), g.I2PKeys, g.getOptions())
|
||||
log.WithField("address", g.ServiceKeys.Address.Base32()).Debug("Creating stream session with keys")
|
||||
log.Println("Creating stream session with keys:", g.ServiceKeys.Address.Base32())
|
||||
g.StreamSession, err = g.SAM.NewStreamSession(g.getName(), *g.ServiceKeys, g.getOptions())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create stream session")
|
||||
return nil, fmt.Errorf("onramp setupStreamSession: %v", err)
|
||||
}
|
||||
log.Debug("Stream session created successfully")
|
||||
return g.StreamSession, nil
|
||||
}
|
||||
return g.StreamSession, nil
|
||||
}
|
||||
|
||||
func (g *Garlic) setupDatagramSession() (*sam3.DatagramSession, error) {
|
||||
if g.DatagramSession == nil {
|
||||
log.WithField("name", g.getName()).Debug("Setting up datagram session")
|
||||
var err error
|
||||
g.ServiceKeys, err = g.Keys()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keys for datagram session")
|
||||
return nil, fmt.Errorf("onramp setupDatagramSession: %v", err)
|
||||
}
|
||||
log.WithField("address", g.ServiceKeys.Address.Base32()).Debug("Creating datagram session with keys")
|
||||
log.Println("Creating datagram session with keys:", g.ServiceKeys.Address.Base32())
|
||||
g.DatagramSession, err = g.SAM.NewDatagramSession(g.getName(), *g.ServiceKeys, g.getOptions(), 0)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create datagram session")
|
||||
return nil, fmt.Errorf("onramp setupDatagramSession: %v", err)
|
||||
}
|
||||
log.Debug("Datagram session created successfully")
|
||||
return g.DatagramSession, nil
|
||||
}
|
||||
|
||||
log.Debug("Using existing datagram session")
|
||||
return g.DatagramSession, nil
|
||||
}
|
||||
|
||||
// NewListener returns a net.Listener for the Garlic structure's I2P keys.
|
||||
// accepts a variable list of arguments, arguments after the first one are ignored.
|
||||
func (g *Garlic) NewListener(n, addr string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": n,
|
||||
"address": addr,
|
||||
"name": g.getName(),
|
||||
}).Debug("Creating new listener")
|
||||
listener, err := g.Listen(n)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create listener")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully created listener")
|
||||
return listener, nil
|
||||
// return g.Listen(n)
|
||||
}
|
||||
|
||||
// Listen returns a net.Listener for the Garlic structure's I2P keys.
|
||||
func (g *Garlic) Listen() (net.Listener, error) {
|
||||
// accepts a variable list of arguments, arguments after the first one are ignored.
|
||||
func (g *Garlic) Listen(args ...string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"args": args,
|
||||
"name": g.getName(),
|
||||
}).Debug("Setting up listener")
|
||||
|
||||
listener, err := g.OldListen(args...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create listener")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully created listener")
|
||||
return listener, nil
|
||||
// return g.OldListen(args...)
|
||||
}
|
||||
|
||||
// OldListen returns a net.Listener for the Garlic structure's I2P keys.
|
||||
// accepts a variable list of arguments, arguments after the first one are ignored.
|
||||
func (g *Garlic) OldListen(args ...string) (net.Listener, error) {
|
||||
log.WithField("args", args).Debug("Starting OldListen")
|
||||
if len(args) > 0 {
|
||||
protocol := args[0]
|
||||
log.WithField("protocol", protocol).Debug("Checking protocol type")
|
||||
// if args[0] == "tcp" || args[0] == "tcp6" || args[0] == "st" || args[0] == "st6" {
|
||||
if protocol == "tcp" || protocol == "tcp6" || protocol == "st" || protocol == "st6" {
|
||||
log.Debug("Using TCP stream listener")
|
||||
return g.ListenStream()
|
||||
//} else if args[0] == "udp" || args[0] == "udp6" || args[0] == "dg" || args[0] == "dg6" {
|
||||
} else if protocol == "udp" || protocol == "udp6" || protocol == "dg" || protocol == "dg6" {
|
||||
log.Debug("Using UDP datagram listener")
|
||||
pk, err := g.ListenPacket()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create packet listener")
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Successfully created datagram session")
|
||||
return pk.(*sam3.DatagramSession), nil
|
||||
}
|
||||
|
||||
}
|
||||
log.Debug("No protocol specified, defaulting to stream listener")
|
||||
return g.ListenStream()
|
||||
}
|
||||
|
||||
// Listen returns a net.Listener for the Garlic structure's I2P keys.
|
||||
func (g *Garlic) ListenStream() (net.Listener, error) {
|
||||
log.Debug("Setting up stream listener")
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session for stream listener")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.StreamSession, err = g.setupStreamSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to setup stream session")
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
if g.StreamListener == nil {
|
||||
log.Debug("Creating new stream listener")
|
||||
g.StreamListener, err = g.StreamSession.Listen()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create stream listener")
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
log.Debug("Stream listener created successfully")
|
||||
}
|
||||
return g.StreamListener, nil
|
||||
}
|
||||
|
||||
// ListenPacket returns a net.PacketConn for the Garlic structure's I2P keys.
|
||||
func (g *Garlic) ListenPacket() (net.PacketConn, error) {
|
||||
log.Debug("Setting up packet connection")
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session for packet connection")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.DatagramSession, err = g.setupDatagramSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to setup datagram session")
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
log.Debug("Packet connection successfully established")
|
||||
return g.DatagramSession, nil
|
||||
}
|
||||
|
||||
// ListenTLS returns a net.Listener for the Garlic structure's I2P keys,
|
||||
// which also uses TLS either for additional encryption, authentication,
|
||||
// or browser-compatibility.
|
||||
func (g *Garlic) ListenTLS() (net.Listener, error) {
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.StreamSession, err = g.setupStreamSession(); err != nil {
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
if g.StreamListener == nil {
|
||||
g.StreamListener, err = g.StreamSession.Listen()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
func (g *Garlic) ListenTLS(args ...string) (net.Listener, error) {
|
||||
log.WithField("args", args).Debug("Starting TLS listener")
|
||||
listener, err := g.Listen(args...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create base listener")
|
||||
return nil, err
|
||||
}
|
||||
cert, err := g.TLSKeys()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get TLS keys")
|
||||
return nil, fmt.Errorf("onramp ListenTLS: %v", err)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
protocol := args[0]
|
||||
log.WithField("protocol", protocol).Debug("Creating TLS listener for protocol")
|
||||
|
||||
// if args[0] == "tcp" || args[0] == "tcp6" || args[0] == "st" || args[0] == "st6" {
|
||||
if protocol == "tcp" || protocol == "tcp6" || protocol == "st" || protocol == "st6" {
|
||||
log.Debug("Creating TLS stream listener")
|
||||
return tls.NewListener(
|
||||
g.StreamListener,
|
||||
&tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
), nil
|
||||
//} else if args[0] == "udp" || args[0] == "udp6" || args[0] == "dg" || args[0] == "dg6" {
|
||||
} else if protocol == "udp" || protocol == "udp6" || protocol == "dg" || protocol == "dg6" {
|
||||
log.Debug("Creating TLS datagram listener")
|
||||
return tls.NewListener(
|
||||
g.DatagramSession,
|
||||
&tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Debug("No protocol specified, using stream listener")
|
||||
g.StreamListener = listener.(*sam3.StreamListener)
|
||||
}
|
||||
log.Debug("Successfully created TLS listener")
|
||||
return tls.NewListener(
|
||||
g.StreamListener,
|
||||
&tls.Config{
|
||||
@@ -127,58 +319,143 @@ func (g *Garlic) ListenTLS() (net.Listener, error) {
|
||||
|
||||
// Dial returns a net.Conn for the Garlic structure's I2P keys.
|
||||
func (g *Garlic) Dial(net, addr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": net,
|
||||
"address": addr,
|
||||
}).Debug("Attempting to dial")
|
||||
if !strings.Contains(addr, ".i2p") {
|
||||
log.Debug("Non-I2P address detected, returning null connection")
|
||||
return &NullConn{}, nil
|
||||
}
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.StreamSession, err = g.setupStreamSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to setup stream session")
|
||||
return nil, fmt.Errorf("onramp Dial: %v", err)
|
||||
}
|
||||
return g.StreamSession.Dial(net, addr)
|
||||
log.Debug("Attempting to establish connection")
|
||||
conn, err := g.StreamSession.Dial(net, addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to establish connection")
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Successfully established connection")
|
||||
return conn, nil
|
||||
// return g.StreamSession.Dial(net, addr)
|
||||
}
|
||||
|
||||
// DialContext returns a net.Conn for the Garlic structure's I2P keys.
|
||||
func (g *Garlic) DialContext(ctx context.Context, net, addr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": net,
|
||||
"address": addr,
|
||||
}).Debug("Attempting to dial with context")
|
||||
if !strings.Contains(addr, ".i2p") {
|
||||
log.Debug("Non-I2P address detected, returning null connection")
|
||||
return &NullConn{}, nil
|
||||
}
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.StreamSession, err = g.setupStreamSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to setup stream session")
|
||||
return nil, fmt.Errorf("onramp Dial: %v", err)
|
||||
}
|
||||
log.Debug("Attempting to establish connection with context")
|
||||
conn, err := g.StreamSession.DialContext(ctx, net, addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to establish connection")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully established connection")
|
||||
return conn, nil
|
||||
// return g.StreamSession.DialContext(ctx, net, addr)
|
||||
}
|
||||
|
||||
// Close closes the Garlic structure's sessions and listeners.
|
||||
func (g *Garlic) Close() error {
|
||||
log.WithField("name", g.getName()).Debug("Closing Garlic sessions")
|
||||
e1 := g.StreamSession.Close()
|
||||
var err error
|
||||
if e1 != nil {
|
||||
log.WithError(e1).Error("Failed to close stream session")
|
||||
err = fmt.Errorf("onramp Close: %v", e1)
|
||||
} else {
|
||||
log.Debug("Stream session closed successfully")
|
||||
}
|
||||
e2 := g.SAM.Close()
|
||||
if e2 != nil {
|
||||
log.WithError(e2).Error("Failed to close SAM session")
|
||||
err = fmt.Errorf("onramp Close: %v %v", e1, e2)
|
||||
} else {
|
||||
log.Debug("SAM session closed successfully")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
log.Debug("All sessions closed successfully")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Keys returns the I2PKeys for the Garlic structure. If none
|
||||
// exist, they are created and stored.
|
||||
func (g *Garlic) Keys() (i2pkeys.I2PKeys, error) {
|
||||
func (g *Garlic) Keys() (*i2pkeys.I2PKeys, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"name": g.getName(),
|
||||
"address": g.getAddr(),
|
||||
}).Debug("Retrieving I2P keys")
|
||||
|
||||
keys, err := I2PKeys(g.getName(), g.getAddr())
|
||||
if err != nil {
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp Keys: %v", err)
|
||||
log.WithError(err).Error("Failed to get I2P keys")
|
||||
return &i2pkeys.I2PKeys{}, fmt.Errorf("onramp Keys: %v", err)
|
||||
}
|
||||
return keys, nil
|
||||
log.Debug("Successfully retrieved I2P keys")
|
||||
return &keys, nil
|
||||
}
|
||||
|
||||
func (g *Garlic) DeleteKeys() error {
|
||||
return DeleteGarlicKeys(g.getName())
|
||||
// return DeleteGarlicKeys(g.getName())
|
||||
log.WithField("name", g.getName()).Debug("Attempting to delete Garlic keys")
|
||||
err := DeleteGarlicKeys(g.getName())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to delete Garlic keys")
|
||||
}
|
||||
log.Debug("Successfully deleted Garlic keys")
|
||||
return err
|
||||
}
|
||||
|
||||
// NewGarlic returns a new Garlic struct. It is immediately ready to use with
|
||||
// I2P streaming.
|
||||
func NewGarlic(tunName, samAddr string, options []string) (*Garlic, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"tunnel_name": tunName,
|
||||
"sam_address": samAddr,
|
||||
"options": options,
|
||||
}).Debug("Creating new Garlic instance")
|
||||
|
||||
g := new(Garlic)
|
||||
g.name = tunName
|
||||
g.addr = samAddr
|
||||
g.opts = options
|
||||
var err error
|
||||
if g.SAM, err = g.samSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM session")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
if g.StreamSession, err = g.setupStreamSession(); err != nil {
|
||||
log.WithError(err).Error("Failed to setup stream session")
|
||||
return nil, fmt.Errorf("onramp NewGarlic: %v", err)
|
||||
}
|
||||
|
||||
log.Debug("Successfully created new Garlic instance")
|
||||
return g, nil
|
||||
}
|
||||
|
||||
@@ -187,49 +464,74 @@ func NewGarlic(tunName, samAddr string, options []string) (*Garlic, error) {
|
||||
// This is permanent and irreversible, and will change the onion service
|
||||
// address.
|
||||
func DeleteGarlicKeys(tunName string) error {
|
||||
log.WithField("tunnel_name", tunName).Debug("Attempting to delete Garlic keys")
|
||||
keystore, err := I2PKeystorePath()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
return fmt.Errorf("onramp DeleteGarlicKeys: discovery error %v", err)
|
||||
}
|
||||
keyspath := filepath.Join(keystore, tunName+".i2p.private")
|
||||
log.WithField("path", keyspath).Debug("Deleting key file")
|
||||
if err := os.Remove(keyspath); err != nil {
|
||||
log.WithError(err).WithField("path", keyspath).Error("Failed to delete key file")
|
||||
return fmt.Errorf("onramp DeleteGarlicKeys: %v", err)
|
||||
}
|
||||
log.Debug("Successfully deleted Garlic keys")
|
||||
return nil
|
||||
}
|
||||
|
||||
// I2PKeys returns the I2PKeys at the keystore directory for the given
|
||||
// tunnel name. If none exist, they are created and stored.
|
||||
func I2PKeys(tunName, samAddr string) (i2pkeys.I2PKeys, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"tunnel_name": tunName,
|
||||
"sam_address": samAddr,
|
||||
}).Debug("Looking up I2P keys")
|
||||
|
||||
keystore, err := I2PKeystorePath()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp I2PKeys: discovery error %v", err)
|
||||
}
|
||||
keyspath := filepath.Join(keystore, tunName+".i2p.private")
|
||||
log.WithField("path", keyspath).Debug("Checking for existing keys")
|
||||
info, err := os.Stat(keyspath)
|
||||
if info != nil {
|
||||
if info.Size() == 0 {
|
||||
log.WithField("path", keyspath).Debug("Keystore empty, will regenerate keys")
|
||||
log.Println("onramp I2PKeys: keystore empty, re-generating keys")
|
||||
} else {
|
||||
log.WithField("path", keyspath).Debug("Found existing keystore")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.WithField("path", keyspath).Debug("Keys not found, generating new keys")
|
||||
sam, err := sam3.NewSAM(samAddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create SAM connection")
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp I2PKeys: SAM error %v", err)
|
||||
}
|
||||
log.Debug("SAM connection established")
|
||||
keys, err := sam.NewKeys(tunName)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate new keys")
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp I2PKeys: keygen error %v", err)
|
||||
}
|
||||
log.Debug("New keys generated successfully")
|
||||
if err = i2pkeys.StoreKeys(keys, keyspath); err != nil {
|
||||
log.WithError(err).WithField("path", keyspath).Error("Failed to store generated keys")
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp I2PKeys: store error %v", err)
|
||||
}
|
||||
log.WithField("path", keyspath).Debug("Successfully stored new keys")
|
||||
return keys, nil
|
||||
} else {
|
||||
log.WithField("path", keyspath).Debug("Loading existing keys")
|
||||
keys, err := i2pkeys.LoadKeys(keyspath)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", keyspath).Error("Failed to load existing keys")
|
||||
return i2pkeys.I2PKeys{}, fmt.Errorf("onramp I2PKeys: load error %v", err)
|
||||
}
|
||||
log.Debug("Successfully loaded existing keys")
|
||||
return keys, nil
|
||||
}
|
||||
}
|
||||
@@ -239,18 +541,35 @@ var garlics map[string]*Garlic
|
||||
// CloseAllGarlic closes all garlics managed by the onramp package. It does not
|
||||
// affect objects instantiated by an app.
|
||||
func CloseAllGarlic() {
|
||||
log.WithField("count", len(garlics)).Debug("Closing all Garlic connections")
|
||||
for i, g := range garlics {
|
||||
log.WithFields(logrus.Fields{
|
||||
"index": i,
|
||||
"name": g.name,
|
||||
}).Debug("Closing Garlic connection")
|
||||
|
||||
log.Println("Closing garlic", g.name)
|
||||
CloseGarlic(i)
|
||||
}
|
||||
log.Debug("All Garlic connections closed")
|
||||
}
|
||||
|
||||
// CloseGarlic closes the Garlic at the given index. It does not affect Garlic
|
||||
// objects instantiated by an app.
|
||||
func CloseGarlic(tunName string) {
|
||||
log.WithField("tunnel_name", tunName).Debug("Attempting to close Garlic connection")
|
||||
g, ok := garlics[tunName]
|
||||
if ok {
|
||||
g.Close()
|
||||
log.Debug("Found Garlic connection, closing")
|
||||
// g.Close()
|
||||
err := g.Close()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error closing Garlic connection")
|
||||
} else {
|
||||
log.Debug("Successfully closed Garlic connection")
|
||||
}
|
||||
} else {
|
||||
log.Debug("No Garlic connection found for tunnel name")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,11 +581,18 @@ var SAM_ADDR = "127.0.0.1:7656"
|
||||
// corresponding to a structure managed by the onramp library
|
||||
// and not instantiated by an app.
|
||||
func ListenGarlic(network, keys string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": network,
|
||||
"keys": keys,
|
||||
"sam_addr": SAM_ADDR,
|
||||
}).Debug("Creating new Garlic listener")
|
||||
g, err := NewGarlic(keys, SAM_ADDR, OPT_DEFAULTS)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new Garlic")
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
garlics[keys] = g
|
||||
log.Debug("Successfully created Garlic listener")
|
||||
return g.Listen()
|
||||
}
|
||||
|
||||
@@ -274,10 +600,26 @@ func ListenGarlic(network, keys string) (net.Listener, error) {
|
||||
// corresponding to a structure managed by the onramp library
|
||||
// and not instantiated by an app.
|
||||
func DialGarlic(network, addr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": network,
|
||||
"address": addr,
|
||||
"sam_addr": SAM_ADDR,
|
||||
}).Debug("Creating new Garlic connection")
|
||||
|
||||
g, err := NewGarlic(addr, SAM_ADDR, OPT_DEFAULTS)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new Garlic")
|
||||
return nil, fmt.Errorf("onramp Dial: %v", err)
|
||||
}
|
||||
garlics[addr] = g
|
||||
return g.Dial(network, addr)
|
||||
log.WithField("address", addr).Debug("Attempting to dial")
|
||||
conn, err := g.Dial(network, addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to dial connection")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully established Garlic connection")
|
||||
return conn, nil
|
||||
// return g.Dial(network, addr)
|
||||
}
|
||||
|
15
garlic_config.go
Normal file
15
garlic_config.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package onramp
|
||||
|
||||
import "github.com/go-i2p/sam3"
|
||||
|
||||
var (
|
||||
OPT_DEFAULTS = sam3.Options_Default
|
||||
OPT_WIDE = sam3.Options_Wide
|
||||
)
|
||||
|
||||
var (
|
||||
OPT_HUGE = sam3.Options_Humongous
|
||||
OPT_LARGE = sam3.Options_Large
|
||||
OPT_MEDIUM = sam3.Options_Medium
|
||||
OPT_SMALL = sam3.Options_Small
|
||||
)
|
@@ -6,8 +6,7 @@ package onramp
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -17,7 +16,10 @@ import (
|
||||
func TestBareGarlic(t *testing.T) {
|
||||
fmt.Println("TestBareGarlic Countdown")
|
||||
Sleep(5)
|
||||
garlic := &Garlic{}
|
||||
garlic, err := NewGarlic("test123", "localhost:7656", OPT_WIDE)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer garlic.Close()
|
||||
listener, err := garlic.ListenTLS()
|
||||
if err != nil {
|
||||
@@ -29,9 +31,14 @@ func TestBareGarlic(t *testing.T) {
|
||||
fmt.Fprintf(w, "Hello, %q", r.URL.Path)
|
||||
})
|
||||
go Serve(listener)
|
||||
Sleep(15)
|
||||
garlic2, err := NewGarlic("test321", "localhost:7656", OPT_WIDE)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer garlic2.Close()
|
||||
Sleep(60)
|
||||
transport := http.Transport{
|
||||
Dial: garlic.Dial,
|
||||
Dial: garlic2.Dial,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
@@ -45,7 +52,7 @@ func TestBareGarlic(t *testing.T) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
fmt.Println(resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
19
go.mod
19
go.mod
@@ -1,15 +1,20 @@
|
||||
module github.com/eyedeekay/onramp
|
||||
module github.com/go-i2p/onramp
|
||||
|
||||
go 1.18
|
||||
go 1.23.3
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7
|
||||
github.com/eyedeekay/sam3 v0.33.3
|
||||
github.com/go-i2p/i2pkeys v0.33.10-0.20241113193422-e10de5e60708
|
||||
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c
|
||||
github.com/go-i2p/sam3 v0.33.9
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
golang.org/x/crypto v0.29.0 // indirect
|
||||
golang.org/x/net v0.31.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
)
|
||||
|
93
go.sum
93
go.sum
@@ -1,89 +1,40 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220803204630-910de44ac829 h1:uXKTvYvSGuzAHzmT0YgPu3XZjZOlH1lLwrgWkymz934=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220803204630-910de44ac829/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7 h1:or9gYJ9VQN8YGoC0yKRC5lAWna2TaDMGZH/JFhwoJ4Q=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
||||
github.com/eyedeekay/sam3 v0.33.3 h1:VeN4nYWWeGfnnnHIPg0fjk+Kt2DI+6RSYcJrb2M7C4c=
|
||||
github.com/eyedeekay/sam3 v0.33.3/go.mod h1:sPtlI4cRm7wD0UywOzLPvvdY1G++vBSK3n+jiIGqWlU=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
|
||||
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio v1.0.0/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
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/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
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/go-i2p/i2pkeys v0.0.0-20241108200332-e4f5ccdff8c4/go.mod h1:m5TlHjPZrU5KbTd7Lr+I2rljyC6aJ88HdkeMQXV0U0E=
|
||||
github.com/go-i2p/i2pkeys v0.33.10-0.20241113193422-e10de5e60708 h1:Tiy9IBwi21maNpK74yCdHursJJMkyH7w87tX1nXGWzg=
|
||||
github.com/go-i2p/i2pkeys v0.33.10-0.20241113193422-e10de5e60708/go.mod h1:m5TlHjPZrU5KbTd7Lr+I2rljyC6aJ88HdkeMQXV0U0E=
|
||||
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c h1:VTiECn3dFEmUlZjto+wOwJ7SSJTHPLyNprQMR5HzIMI=
|
||||
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c/go.mod h1:te7Zj3g3oMeIl8uBXAgO62UKmZ6m6kHRNg1Mm+X8Hzk=
|
||||
github.com/go-i2p/sam3 v0.33.9 h1:3a+gunx75DFc6jxloUZTAVJbdP6736VU1dy2i7I9fKA=
|
||||
github.com/go-i2p/sam3 v0.33.9/go.mod h1:oDuV145l5XWKKafeE4igJHTDpPwA0Yloz9nyKKh92eo=
|
||||
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/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxzAnkLeoEbqHEerI4eSw6ua+RaIB0S4jMV21RAs=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
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/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 h1:N9Vc/rorQUDes6B9CNdIxAn5jODGj2wzfrei2x4wNj4=
|
||||
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 h1:9vYwv7OjYaky/tlAeD7C4oC9EsPTlaFl1H2jS++V+ME=
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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/text v0.3.6/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
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-20191204190536-9bdfabe68543/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
110
index.html
110
index.html
@@ -7,6 +7,7 @@
|
||||
<meta name="description" content="onramp.git" />
|
||||
<meta name="keywords" content="main" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="navbar">
|
||||
@@ -16,6 +17,11 @@
|
||||
<div id="shownav">
|
||||
<div id="hidenav">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="..">
|
||||
Up one level ^
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html">
|
||||
index
|
||||
@@ -45,22 +51,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1>
|
||||
<a href="/">
|
||||
onramp
|
||||
<a href="#onramp" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
onramp
|
||||
</h1>
|
||||
<p>
|
||||
High-level, easy-to-use listeners and clients for I2P and onion URL’s from Go.
|
||||
High-level, easy-to-use listeners and clients for I2P and onion URL's from Go.
|
||||
Provides only the most widely-used functions in a basic way. It expects nothing
|
||||
from the users, an otherwise empty instance of the structs will listen and dial
|
||||
I2P Streaming and Tor TCP sessions successfully.
|
||||
</p>
|
||||
<p>
|
||||
In all cases, it assumes that keys are “persistent” in that they are managed
|
||||
In all cases, it assumes that keys are "persistent" in that they are managed
|
||||
maintained between usages of the same application in the same configuration.
|
||||
This means that hidden services will maintain their identities, and that clients
|
||||
will always have the same return addresses. If you don’t want this behavior,
|
||||
make sure to delete the “keystore” when your app closes or when your application
|
||||
will always have the same return addresses. If you don't want this behavior,
|
||||
make sure to delete the "keystore" when your app closes or when your application
|
||||
needs to cycle keys by calling the
|
||||
<code>
|
||||
Garlic.DeleteKeys()
|
||||
@@ -84,12 +91,18 @@
|
||||
</strong>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days.
|
||||
</p>
|
||||
<h2>
|
||||
<a href="#usage" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Usage
|
||||
</h2>
|
||||
<p>
|
||||
Basic usage is designed to be very simple, import the package and instantiate
|
||||
a struct and you’re ready to go.
|
||||
a struct and you're ready to go.
|
||||
</p>
|
||||
<p>
|
||||
For more extensive examples, see:
|
||||
@@ -98,6 +111,9 @@
|
||||
</a>
|
||||
</p>
|
||||
<h3>
|
||||
<a href="#i2p-garlic-usage" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
I2P(Garlic) Usage:
|
||||
</h3>
|
||||
<p>
|
||||
@@ -107,26 +123,31 @@
|
||||
</code>
|
||||
struct.
|
||||
</p>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"log"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"log"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
garlic := &onramp.Garlic{}
|
||||
defer garlic.Close()
|
||||
listener, err := garlic.Listen()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
}
|
||||
</code></pre>
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>garlic</span> <span>:=</span> <span>&</span><span>onramp</span><span>.</span><span>Garlic</span><span>{</span><span>}</span>
|
||||
<span>defer</span> <span>garlic</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>listener</span><span>,</span> <span>err</span> <span>:=</span> <span>garlic</span><span>.</span><span>Listen</span><span>(</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>listener</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<h3>
|
||||
<a href="#tor-onion-usage" rel="nofollow">
|
||||
<span></span>
|
||||
</a>
|
||||
Tor(Onion) Usage:
|
||||
</h3>
|
||||
<p>
|
||||
@@ -136,25 +157,36 @@ func main() {
|
||||
</code>
|
||||
struct.
|
||||
</p>
|
||||
<pre><code>
|
||||
package main
|
||||
<div>
|
||||
<pre>
|
||||
<span>package</span> <span>main</span>
|
||||
|
||||
import (
|
||||
"log"
|
||||
<span>import</span> <span>(</span>
|
||||
<span>"log"</span>
|
||||
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
<span>"github.com/eyedeekay/onramp"</span>
|
||||
<span>)</span>
|
||||
|
||||
func main() {
|
||||
onion := &onramp.Onion{}
|
||||
defer garlic.Close()
|
||||
listener, err := onion.Listen()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
}
|
||||
</code></pre>
|
||||
<span>func</span> <span>main</span><span>(</span><span>)</span> <span>{</span>
|
||||
<span>onion</span> <span>:=</span> <span>&</span><span>onramp</span><span>.</span><span>Onion</span><span>{</span><span>}</span>
|
||||
<span>defer</span> <span>garlic</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>listener</span><span>,</span> <span>err</span> <span>:=</span> <span>onion</span><span>.</span><span>Listen</span><span>(</span><span>)</span>
|
||||
<span>if</span> <span>err</span> <span>!=</span> <span>nil</span> <span>{</span>
|
||||
<span>log</span><span>.</span><span>Fatal</span><span>(</span><span>err</span><span>)</span>
|
||||
<span>}</span>
|
||||
<span>defer</span> <span>listener</span><span>.</span><span>Close</span><span>(</span><span>)</span>
|
||||
<span>}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div id="sourcecode">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/eyedeekay/onramp.git">
|
||||
Source Code: (https://github.com/eyedeekay/onramp.git)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#show">
|
||||
Show license
|
||||
|
44
nullconn.go
Normal file
44
nullconn.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package onramp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NullConn struct {
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (nc *NullConn) Read(b []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (nc *NullConn) Write(b []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (nc *NullConn) Close() error { return nil }
|
||||
|
||||
func (nc *NullConn) LocalAddr() net.Addr {
|
||||
if nc.Conn != nil {
|
||||
return nc.Conn.LocalAddr()
|
||||
}
|
||||
return &net.IPAddr{
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NullConn) RemoteAddr() net.Addr {
|
||||
if nc.Conn != nil {
|
||||
return nc.Conn.RemoteAddr()
|
||||
}
|
||||
return &net.IPAddr{
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NullConn) SetDeadline(t time.Time) error { return nil }
|
||||
|
||||
func (nc *NullConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
|
||||
func (nc *NullConn) SetWriteDeadline(t time.Time) error { return nil }
|
185
onion.go
185
onion.go
@@ -7,12 +7,12 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
)
|
||||
@@ -66,23 +66,29 @@ func (o *Onion) getDialConf() *tor.DialConf {
|
||||
|
||||
func (o *Onion) getTor() *tor.Tor {
|
||||
if torp == nil {
|
||||
log.Debug("Initializing new Tor instance")
|
||||
var err error
|
||||
torp, err = tor.Start(o.getContext(), o.getStartConf())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.WithError(err).Error("Failed to start Tor")
|
||||
panic(err) // return nil instead?
|
||||
}
|
||||
log.Debug("Tor instance started successfully")
|
||||
}
|
||||
return torp
|
||||
}
|
||||
|
||||
func (o *Onion) getDialer() *tor.Dialer {
|
||||
//if o.Dialer == nil {
|
||||
//var err error
|
||||
//o.Dialer, err
|
||||
// if o.Dialer == nil {
|
||||
// var err error
|
||||
// o.Dialer, err
|
||||
log.Debug("Creating new Tor dialer")
|
||||
dialer, err := o.getTor().Dialer(o.getContext(), o.getDialConf())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Tor dialer")
|
||||
panic(err)
|
||||
}
|
||||
log.Debug("Tor dialer created successfully")
|
||||
//}
|
||||
//return o.Dialer
|
||||
return dialer
|
||||
@@ -90,23 +96,71 @@ func (o *Onion) getDialer() *tor.Dialer {
|
||||
|
||||
func (o *Onion) getName() string {
|
||||
if o.name == "" {
|
||||
o.name = "onramp"
|
||||
o.name = "onramp-onion"
|
||||
}
|
||||
return o.name
|
||||
}
|
||||
|
||||
// ListenOnion returns a net.Listener which will listen on an onion
|
||||
// NewListener returns a net.Listener which will listen on an onion
|
||||
// address, and will automatically generate a keypair and store it.
|
||||
func (o *Onion) Listen() (net.Listener, error) {
|
||||
return o.getTor().Listen(o.getContext(), o.getListenConf())
|
||||
// the args are always ignored
|
||||
func (o *Onion) NewListener(n, addr string) (net.Listener, error) {
|
||||
return o.Listen(n)
|
||||
}
|
||||
|
||||
func (o *Onion) ListenTLS() (net.Listener, error) {
|
||||
// Listen returns a net.Listener which will listen on an onion
|
||||
// address, and will automatically generate a keypair and store it.
|
||||
// the args are always ignored
|
||||
func (o *Onion) Listen(args ...string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"args": args,
|
||||
"name": o.getName(),
|
||||
}).Debug("Setting up Onion listener")
|
||||
listener, err := o.OldListen(args...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Onion listener")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully created Onion listener")
|
||||
return listener, nil
|
||||
// return o.OldListen(args...)
|
||||
}
|
||||
|
||||
// OldListen returns a net.Listener which will listen on an onion
|
||||
// address, and will automatically generate a keypair and store it.
|
||||
// the args are always ignored
|
||||
func (o *Onion) OldListen(args ...string) (net.Listener, error) {
|
||||
log.WithField("name", o.getName()).Debug("Creating Tor listener")
|
||||
|
||||
listener, err := o.getTor().Listen(o.getContext(), o.getListenConf())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Tor listener")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully created Tor listener")
|
||||
return listener, nil
|
||||
// return o.getTor().Listen(o.getContext(), o.getListenConf())
|
||||
}
|
||||
|
||||
// ListenTLS returns a net.Listener which will apply TLS encryption
|
||||
// to the onion listener, which will not be decrypted until it reaches
|
||||
// the browser
|
||||
func (o *Onion) ListenTLS(args ...string) (net.Listener, error) {
|
||||
log.WithField("args", args).Debug("Setting up TLS Onion listener")
|
||||
cert, err := o.TLSKeys()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get TLS keys")
|
||||
return nil, fmt.Errorf("onramp ListenTLS: %v", err)
|
||||
}
|
||||
log.Debug("Creating base Tor listener")
|
||||
l, err := o.getTor().Listen(o.getContext(), o.getListenConf())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create base Tor listener")
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Wrapping Tor listener with TLS")
|
||||
return tls.NewListener(
|
||||
l,
|
||||
&tls.Config{
|
||||
@@ -117,23 +171,56 @@ func (o *Onion) ListenTLS() (net.Listener, error) {
|
||||
|
||||
// Dial returns a net.Conn to the given onion address or clearnet address.
|
||||
func (o *Onion) Dial(net, addr string) (net.Conn, error) {
|
||||
return o.getDialer().DialContext(o.getContext(), net, addr)
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": net,
|
||||
"address": addr,
|
||||
}).Debug("Attempting to dial via Tor")
|
||||
conn, err := o.getDialer().DialContext(o.getContext(), net, addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to establish Tor connection")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully established Tor connection")
|
||||
return conn, nil
|
||||
// return o.getDialer().DialContext(o.getContext(), net, addr)
|
||||
}
|
||||
|
||||
// Close closes the Onion Service and all associated resources.
|
||||
func (o *Onion) Close() error {
|
||||
return o.getTor().Close()
|
||||
log.WithField("name", o.getName()).Debug("Closing Onion service")
|
||||
|
||||
err := o.getTor().Close()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to close Tor instance")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug("Successfully closed Onion service")
|
||||
return nil
|
||||
// return o.getTor().Close()
|
||||
}
|
||||
|
||||
// Keys returns the keys for the Onion
|
||||
func (o *Onion) Keys() (ed25519.KeyPair, error) {
|
||||
return TorKeys(o.getName())
|
||||
log.WithField("name", o.getName()).Debug("Retrieving Onion keys")
|
||||
|
||||
keys, err := TorKeys(o.getName())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get Tor keys")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully retrieved Onion keys")
|
||||
return keys, nil
|
||||
// return TorKeys(o.getName())
|
||||
}
|
||||
|
||||
// DeleteKeys deletes the keys at the given key name in the key store.
|
||||
// This is permanent and irreversible, and will change the onion service
|
||||
// address.
|
||||
func (g *Onion) DeleteKeys() error {
|
||||
log.WithField("Onion keys", g.getName()).Debug("Deleting Onion keys")
|
||||
return DeleteOnionKeys(g.getName())
|
||||
}
|
||||
|
||||
@@ -148,36 +235,50 @@ func NewOnion(name string) (*Onion, error) {
|
||||
// name in the key store. If the key already exists, it will be
|
||||
// returned. If it does not exist, it will be generated.
|
||||
func TorKeys(keyName string) (ed25519.KeyPair, error) {
|
||||
log.WithField("key_name", keyName).Debug("Getting Tor keys")
|
||||
keystore, err := TorKeystorePath()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
return nil, fmt.Errorf("onramp OnionKeys: discovery error %v", err)
|
||||
}
|
||||
var keys ed25519.KeyPair
|
||||
keysPath := filepath.Join(keystore, keyName+".tor.private")
|
||||
log.WithField("path", keysPath).Debug("Checking for existing keys")
|
||||
if _, err := os.Stat(keysPath); os.IsNotExist(err) {
|
||||
log.Debug("Generating new Tor keys")
|
||||
tkeys, err := ed25519.GenerateKey(nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to generate onion service key, %s", err)
|
||||
log.WithError(err).Error("Failed to generate onion service key")
|
||||
log.Fatal("Unable to generate onion service key")
|
||||
}
|
||||
keys = tkeys
|
||||
|
||||
log.WithField("path", keysPath).Debug("Creating key file")
|
||||
f, err := os.Create(keysPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create Tor keys file for writing, %s", err)
|
||||
log.WithError(err).Error("Failed to create Tor keys file")
|
||||
log.Fatal("Unable to create Tor keys file for writing")
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write(tkeys.PrivateKey())
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to write Tor keys to disk, %s", err)
|
||||
log.WithError(err).Error("Failed to write Tor keys to disk")
|
||||
log.Fatal("Unable to write Tor keys to disk")
|
||||
}
|
||||
log.Debug("Successfully generated and stored new keys")
|
||||
} else if err == nil {
|
||||
tkeys, err := ioutil.ReadFile(keysPath)
|
||||
log.Debug("Loading existing Tor keys")
|
||||
tkeys, err := os.ReadFile(keysPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read Tor keys from disk")
|
||||
log.WithError(err).Error("Failed to read Tor keys from disk")
|
||||
log.Fatal("Unable to read Tor keys from disk")
|
||||
}
|
||||
k := ed25519.FromCryptoPrivateKey(tkeys)
|
||||
keys = k
|
||||
log.Debug("Successfully loaded existing keys")
|
||||
} else {
|
||||
log.Fatalf("Unable to set up Tor keys, %s", err)
|
||||
log.WithError(err).Error("Failed to set up Tor keys")
|
||||
log.Fatal("Unable to set up Tor keys")
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
@@ -187,18 +288,34 @@ var onions map[string]*Onion
|
||||
// CloseAllOnion closes all onions managed by the onramp package. It does not
|
||||
// affect objects instantiated by an app.
|
||||
func CloseAllOnion() {
|
||||
log.WithField("count", len(onions)).Debug("Closing all Onion services")
|
||||
for i, g := range onions {
|
||||
log.Println("Closing onion", g.name)
|
||||
log.WithFields(logrus.Fields{
|
||||
"index": i,
|
||||
"name": g.name,
|
||||
}).Debug("Closing Onion service")
|
||||
CloseOnion(i)
|
||||
}
|
||||
|
||||
log.Debug("All Onion services closed")
|
||||
}
|
||||
|
||||
// CloseOnion closes the Onion at the given index. It does not affect Onion
|
||||
// objects instantiated by an app.
|
||||
func CloseOnion(tunName string) {
|
||||
log.WithField("tunnel_name", tunName).Debug("Attempting to close Onion service")
|
||||
|
||||
g, ok := onions[tunName]
|
||||
if ok {
|
||||
g.Close()
|
||||
log.WithField("name", g.name).Debug("Found Onion service, closing")
|
||||
err := g.Close()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to close Onion service")
|
||||
} else {
|
||||
log.Debug("Successfully closed Onion service")
|
||||
}
|
||||
} else {
|
||||
log.Debug("No Onion service found for tunnel name")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,12 +323,28 @@ func CloseOnion(tunName string) {
|
||||
// corresponding to a structure managed by the onramp library
|
||||
// and not instantiated by an app.
|
||||
func ListenOnion(network, keys string) (net.Listener, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"network": network,
|
||||
"keys": keys,
|
||||
}).Debug("Creating new Onion listener")
|
||||
|
||||
g, err := NewOnion(keys)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new Onion")
|
||||
return nil, fmt.Errorf("onramp Listen: %v", err)
|
||||
}
|
||||
onions[keys] = g
|
||||
return g.Listen()
|
||||
log.Debug("Onion service registered, creating listener")
|
||||
|
||||
listener, err := g.Listen()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Onion listener")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully created Onion listener")
|
||||
return listener, nil
|
||||
// return g.Listen()
|
||||
}
|
||||
|
||||
// DialOnion returns a net.Conn for a onion structure's keys
|
||||
@@ -229,13 +362,19 @@ func DialOnion(network, addr string) (net.Conn, error) {
|
||||
// DeleteOnionKeys deletes the key file at the given path as determined by
|
||||
// keystore + tunName.
|
||||
func DeleteOnionKeys(tunName string) error {
|
||||
log.WithField("tunnel_name", tunName).Debug("Attempting to delete Onion keys")
|
||||
|
||||
keystore, err := TorKeystorePath()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
return fmt.Errorf("onramp DeleteOnionKeys: discovery error %v", err)
|
||||
}
|
||||
keyspath := filepath.Join(keystore, tunName+".i2p.private")
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
if err := os.Remove(keyspath); err != nil {
|
||||
log.WithError(err).WithField("path", keyspath).Error("Failed to delete key file")
|
||||
return fmt.Errorf("onramp DeleteOnionKeys: %v", err)
|
||||
}
|
||||
log.Debug("Successfully deleted Onion keys")
|
||||
return nil
|
||||
}
|
||||
|
@@ -6,8 +6,7 @@ package onramp
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
@@ -15,19 +14,22 @@ import (
|
||||
func TestBareOnion(t *testing.T) {
|
||||
fmt.Println("TestBareOnion Countdown")
|
||||
Sleep(5)
|
||||
onion := &Onion{}
|
||||
onion, err := NewOnion("test123")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer onion.Close()
|
||||
listener, err := onion.ListenTLS()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
log.Println("listener:", listener.Addr().String())
|
||||
//defer listener.Close()
|
||||
// defer listener.Close()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, %q", r.URL.Path)
|
||||
})
|
||||
go Serve(listener)
|
||||
Sleep(15)
|
||||
Sleep(60)
|
||||
transport := http.Transport{
|
||||
Dial: onion.Dial,
|
||||
TLSClientConfig: &tls.Config{
|
||||
@@ -42,7 +44,7 @@ func TestBareOnion(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println("Status:", resp.Status)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
86
proxy.go
Normal file
86
proxy.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package onramp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type OnrampProxy struct {
|
||||
Onion
|
||||
Garlic
|
||||
}
|
||||
|
||||
// Proxy passes requests from a net.Listener to a remote server
|
||||
// without touching them in any way. It can be used as a shortcut,
|
||||
// set up a Garlic or Onion Listener and pass it, along with the
|
||||
// address of a locally running service and the hidden service
|
||||
// listener will expose the local service.
|
||||
// Pass it a regular net.Listener(or a TLS listener if you like),
|
||||
// and an I2P or Onion address, and it will act as a tunnel to a
|
||||
// listening hidden service somewhere.
|
||||
func (p *OnrampProxy) Proxy(list net.Listener, raddr string) error {
|
||||
log.WithFields(logrus.Fields{
|
||||
"remote_address": raddr,
|
||||
"local_address": list.Addr().String(),
|
||||
}).Debug("Starting proxy service")
|
||||
|
||||
for {
|
||||
log.Debug("Waiting for incoming connection")
|
||||
conn, err := list.Accept()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to accept connection")
|
||||
return err
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"local_addr": conn.LocalAddr().String(),
|
||||
"remote_addr": conn.RemoteAddr().String(),
|
||||
}).Debug("Accepted new connection, starting proxy routine")
|
||||
|
||||
go p.proxy(conn, raddr)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *OnrampProxy) proxy(conn net.Conn, raddr string) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"remote_address": raddr,
|
||||
"local_addr": conn.LocalAddr().String(),
|
||||
"remote_addr": conn.RemoteAddr().String(),
|
||||
}).Debug("Setting up proxy connection")
|
||||
|
||||
var remote net.Conn
|
||||
var err error
|
||||
checkaddr := strings.Split(raddr, ":")[0]
|
||||
if strings.HasSuffix(checkaddr, ".i2p") {
|
||||
log.Debug("Detected I2P address, using Garlic connection")
|
||||
remote, err = p.Garlic.Dial("tcp", raddr)
|
||||
} else if strings.HasSuffix(checkaddr, ".onion") {
|
||||
log.Debug("Detected Onion address, using Tor connection")
|
||||
remote, err = p.Onion.Dial("tcp", raddr)
|
||||
} else {
|
||||
log.Debug("Using standard TCP connection")
|
||||
remote, err = net.Dial("tcp", raddr)
|
||||
}
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to establish remote connection")
|
||||
log.Fatal("Cannot dial to remote")
|
||||
}
|
||||
defer remote.Close()
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"local_addr": remote.LocalAddr().String(),
|
||||
"remote_addr": remote.RemoteAddr().String(),
|
||||
}).Debug("Remote connection established, starting bidirectional copy")
|
||||
|
||||
go io.Copy(remote, conn)
|
||||
io.Copy(conn, remote)
|
||||
}
|
||||
|
||||
var proxy *OnrampProxy = &OnrampProxy{}
|
||||
|
||||
func Proxy(list net.Listener, raddr string) error {
|
||||
return proxy.Proxy(list, raddr)
|
||||
}
|
@@ -2,9 +2,9 @@
|
||||
|
||||
GITHUB_USER=eyedeekay
|
||||
GITHUB_REPO=onramp
|
||||
GITHUB_NAME="Initial Release"
|
||||
GITHUB_NAME="Removes unnecessary dependency"
|
||||
GITHUB_DESCRIPTION=$(cat DESC.md)
|
||||
GITHUB_TAG=0.0.2
|
||||
GITHUB_TAG=0.0.5
|
||||
|
||||
github-release release --user "${GITHUB_USER}" \
|
||||
--repo "${GITHUB_REPO}" \
|
||||
|
10
showhider.css
Normal file
10
showhider.css
Normal file
@@ -0,0 +1,10 @@
|
||||
/* 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; }
|
56
tls.go
56
tls.go
@@ -17,6 +17,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cretz/bine/torutil"
|
||||
)
|
||||
|
||||
@@ -24,11 +26,14 @@ import (
|
||||
// if no TLS keys exist, they will be generated. They will be valid for
|
||||
// the .b32.i2p domain.
|
||||
func (g *Garlic) TLSKeys() (tls.Certificate, error) {
|
||||
log.WithField("name", g.getName()).Debug("Getting TLS keys for Garlic service")
|
||||
keys, err := g.Keys()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get I2P keys")
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
base32 := keys.Addr().Base32()
|
||||
log.WithField("base32", base32).Debug("Retrieving TLS certificate for base32 address")
|
||||
return TLSKeys(base32)
|
||||
}
|
||||
|
||||
@@ -36,31 +41,45 @@ func (g *Garlic) TLSKeys() (tls.Certificate, error) {
|
||||
// if no TLS keys exist, they will be generated. They will be valid for
|
||||
// the .onion domain.
|
||||
func (o *Onion) TLSKeys() (tls.Certificate, error) {
|
||||
log.WithField("name", o.getName()).Debug("Getting TLS keys for Onion service")
|
||||
keys, err := o.Keys()
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
onionService := torutil.OnionServiceIDFromPrivateKey(keys.PrivateKey)
|
||||
onionService := torutil.OnionServiceIDFromPrivateKey(keys)
|
||||
log.WithField("onion_service", onionService).Debug("Retrieving TLS certificate for onion service")
|
||||
return TLSKeys(onionService)
|
||||
}
|
||||
|
||||
// TLSKeys returns the TLS certificate and key for the given hostname.
|
||||
func TLSKeys(tlsHost string) (tls.Certificate, error) {
|
||||
log.WithField("host", tlsHost).Debug("Getting TLS certificate and key")
|
||||
tlsCert := tlsHost + ".crt"
|
||||
tlsKey := tlsHost + ".pem"
|
||||
if err := CreateTLSCertificate(tlsHost); nil != err {
|
||||
log.WithError(err).Error("Failed to create TLS certificate")
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
tlsKeystorePath, err := TLSKeystorePath()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get TLS keystore path")
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
tlsCertPath := filepath.Join(tlsKeystorePath, tlsCert)
|
||||
tlsKeyPath := filepath.Join(tlsKeystorePath, tlsKey)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"cert_path": tlsCertPath,
|
||||
"key_path": tlsKeyPath,
|
||||
}).Debug("Loading TLS certificate pair")
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to load TLS certificate pair")
|
||||
return cert, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully loaded TLS certificate and key")
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
@@ -68,6 +87,7 @@ func TLSKeys(tlsHost string) (tls.Certificate, error) {
|
||||
// and stores it in the TLS keystore for the application. If the keys already
|
||||
// exist, generation is skipped.
|
||||
func CreateTLSCertificate(tlsHost string) error {
|
||||
log.WithField("host", tlsHost).Debug("Creating TLS certificate")
|
||||
tlsCertName := tlsHost + ".crt"
|
||||
tlsKeyName := tlsHost + ".pem"
|
||||
tlsKeystorePath, err := TLSKeystorePath()
|
||||
@@ -79,70 +99,102 @@ func CreateTLSCertificate(tlsHost string) error {
|
||||
_, certErr := os.Stat(tlsCert)
|
||||
_, keyErr := os.Stat(tlsKey)
|
||||
if certErr != nil || keyErr != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"cert_exists": certErr == nil,
|
||||
"key_exists": keyErr == nil,
|
||||
"cert_path": tlsCert,
|
||||
"key_path": tlsKey,
|
||||
}).Debug("Certificate or key missing, generating new ones")
|
||||
if certErr != nil {
|
||||
log.WithField("path", tlsCert).Debug("TLS certificate not found")
|
||||
fmt.Printf("Unable to read TLS certificate '%s'\n", tlsCert)
|
||||
}
|
||||
if keyErr != nil {
|
||||
log.WithField("path", tlsKey).Debug("TLS key not found")
|
||||
fmt.Printf("Unable to read TLS key '%s'\n", tlsKey)
|
||||
}
|
||||
|
||||
if err := createTLSCertificate(tlsHost); nil != err {
|
||||
log.WithError(err).Error("Failed to create TLS certificate")
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Debug("TLS certificate and key already exist")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTLSCertificate(host string) error {
|
||||
log.WithField("host", host).Debug("Generating new TLS certificate")
|
||||
fmt.Println("Generating TLS keys. This may take a minute...")
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate private key")
|
||||
return err
|
||||
}
|
||||
|
||||
tlsCert, err := NewTLSCertificate(host, priv)
|
||||
if nil != err {
|
||||
log.WithError(err).Error("Failed to create new TLS certificate")
|
||||
return err
|
||||
}
|
||||
privStore, err := TLSKeystorePath()
|
||||
if nil != err {
|
||||
log.WithError(err).Error("Failed to get keystore path")
|
||||
return err
|
||||
}
|
||||
|
||||
certFile := filepath.Join(privStore, host+".crt")
|
||||
log.WithField("path", certFile).Debug("Saving TLS certificate")
|
||||
// save the TLS certificate
|
||||
certOut, err := os.Create(certFile)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", certFile).Error("Failed to create certificate file")
|
||||
return fmt.Errorf("failed to open %s for writing: %s", host+".crt", err)
|
||||
}
|
||||
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: tlsCert})
|
||||
certOut.Close()
|
||||
log.WithField("path", certFile).Debug("TLS certificate saved successfully")
|
||||
fmt.Printf("\tTLS certificate saved to: %s\n", host+".crt")
|
||||
|
||||
// save the TLS private key
|
||||
privFile := filepath.Join(privStore, host+".pem")
|
||||
log.WithField("path", privFile).Debug("Saving TLS private key")
|
||||
keyOut, err := os.OpenFile(privFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", privFile).Error("Failed to create private key file")
|
||||
return fmt.Errorf("failed to open %s for writing: %v", privFile, err)
|
||||
}
|
||||
secp384r1, err := asn1.Marshal(asn1.ObjectIdentifier{1, 3, 132, 0, 34}) // http://www.ietf.org/rfc/rfc5480.txt
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to marshal EC parameters")
|
||||
return err
|
||||
}
|
||||
pem.Encode(keyOut, &pem.Block{Type: "EC PARAMETERS", Bytes: secp384r1})
|
||||
ecder, err := x509.MarshalECPrivateKey(priv)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to marshal private key")
|
||||
return err
|
||||
}
|
||||
pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: ecder})
|
||||
pem.Encode(keyOut, &pem.Block{Type: "CERTIFICATE", Bytes: tlsCert})
|
||||
|
||||
keyOut.Close()
|
||||
log.WithField("path", privFile).Debug("TLS private key saved successfully")
|
||||
fmt.Printf("\tTLS private key saved to: %s\n", privFile)
|
||||
|
||||
// CRL
|
||||
crlFile := filepath.Join(privStore, host+".crl")
|
||||
log.WithField("path", crlFile).Debug("Creating CRL")
|
||||
crlOut, err := os.OpenFile(crlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("path", crlFile).Error("Failed to create CRL file")
|
||||
return fmt.Errorf("failed to open %s for writing: %s", crlFile, err)
|
||||
}
|
||||
crlcert, err := x509.ParseCertificate(tlsCert)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse certificate for CRL creation")
|
||||
return fmt.Errorf("Certificate with unknown critical extension was not parsed: %s", err)
|
||||
}
|
||||
|
||||
@@ -156,10 +208,12 @@ func createTLSCertificate(host string) error {
|
||||
|
||||
crlBytes, err := crlcert.CreateCRL(rand.Reader, priv, revokedCerts, now, now)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create CRL")
|
||||
return fmt.Errorf("error creating CRL: %s", err)
|
||||
}
|
||||
_, err = x509.ParseDERCRL(crlBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to validate generated CRL")
|
||||
return fmt.Errorf("error reparsing CRL: %s", err)
|
||||
}
|
||||
pem.Encode(crlOut, &pem.Block{Type: "X509 CRL", Bytes: crlBytes})
|
||||
|
Reference in New Issue
Block a user