51 Commits
0.0.2 ... main

Author SHA1 Message Date
idk
48e87d68a9 Merge pull request #2 from urgentquest/main
Utililize go i2p logger (revised)
2025-05-05 18:02:21 -04:00
Call me Phil
3f93dec9db Utililize go i2p logger (#1)
- Drop log.go in favor of using go-i2p/logger
- Fix an occurrence of ioutil deprecation. Bump go version to a recent one
2025-03-30 23:14:21 +00:00
eyedeekay
daeaa91183 update modules 2024-11-16 16:25:24 -05:00
eyedeekay
ed7e6f56ae update release process 2024-11-16 16:23:33 -05:00
eyedeekay
982a496406 update module 2024-11-16 15:51:42 -05:00
eyedeekay
d7abd8af30 don't log in GetJoinedWD for now because it is called prior to 2024-11-16 15:50:58 -05:00
eyedeekay
0d05b3c3f7 update examples 2024-11-14 10:43:17 -05:00
eyedeekay
00aafc2ede fix the broken tests 2024-11-13 14:55:42 -05:00
eyedeekay
8920b7c847 update version 2024-11-13 14:53:54 -05:00
eyedeekay
2791849c67 update modules 2024-11-13 14:52:44 -05:00
eyedeekay
0d9a9ee10a Fix up import paths 2024-11-09 11:54:29 -05:00
eyedeekay
867026628f setup auto-assign workflow 2024-11-08 15:01:15 -05:00
eyedeekay
56eed1e88f Merge branch 'main' of github.com:eyedeekay/onramp 2024-11-08 12:55:30 -05:00
eyedeekay
c4e23394dc change module path 2024-11-08 12:54:30 -05:00
idk
f9fc572938 Merge pull request #1 from hkh4n/logging
Logging
2024-11-05 00:03:47 +00:00
Haris Khan
e184eda3c1 replaced deprecated function 2024-11-04 15:20:23 -05:00
Haris Khan
a0a35dd81c added logging to tls.go 2024-11-04 15:17:48 -05:00
Haris Khan
7ef5793e5a added logging to proxy.go 2024-11-04 15:11:49 -05:00
Haris Khan
c2b8660d5e added logging to onion.go 2024-11-04 15:08:35 -05:00
Haris Khan
680d5c000b added logging to garlic.go 2024-11-04 14:52:43 -05:00
Haris Khan
c2b56d35e2 updated README.md to reflect new logging paradigm 2024-11-04 14:44:07 -05:00
Haris Khan
2a53e8347c added logging to common.go 2024-11-04 11:05:47 -05:00
Haris Khan
dcb997a327 added logging paradigm to log.go 2024-11-04 11:05:39 -05:00
eyedeekay
d6a5a60d6f Fix broken test, fix onion TLS listener which broke 2024-09-17 20:10:29 -04:00
eyedeekay
c60c135814 Update sam3 and i2pkeys to 0.33.8 2024-09-17 19:41:29 -04:00
eyedeekay
8f08410320 add credit for contributions to release info 2024-09-17 19:35:32 -04:00
eyedeekay
cdad2747a7 bump version to 0.33.7 2024-01-09 14:48:35 -05:00
eyedeekay
394c9f9fb8 Update sam3 version to v0.33.7 2024-01-09 14:48:08 -05:00
eyedeekay
f32a695cff stub out libp2p interface 2023-08-06 22:36:36 -04:00
eyedeekay
41dcb29429 temporarily remove WIP libp2p support 2023-07-21 15:24:54 -04:00
eyedeekay
0e2d9a60a4 prepare for official releases 2023-07-21 15:15:29 -04:00
idk
f654f2635b start a libp2p transport 2023-06-25 08:25:19 -04:00
idk
eb11a4ec64 remove gosam from module 2023-01-18 06:53:32 +00:00
idk
e2e443e158 remove gosam from module 2023-01-18 06:53:16 +00:00
idk
c93b68c0ab update sam3 lib 2023-01-16 05:55:07 +00:00
idk
af628a80ce remove bridge attempt for now 2023-01-16 05:54:26 +00:00
idk
c6b30ad4cb remove bridge attempt for now 2023-01-16 05:54:13 +00:00
idk
002fd2f79c bump version 2023-01-07 03:33:41 +00:00
idk
2f2d359ffb change how it expresses addresses on the fly 2023-01-07 03:32:13 +00:00
idk
59c4ed7e73 Add DialContext 2022-12-29 20:56:37 +00:00
idk
dc495c94f6 Add datagram sessions 2022-12-29 20:03:42 +00:00
idk
64cb1842d0 update EXAMPLE.html 2022-08-29 01:01:01 -04:00
idk
55f43b8382 update DOCS.html 2022-08-29 01:00:58 -04:00
idk
1c866297b5 update DESC.html 2022-08-29 01:00:55 -04:00
idk
8170ddbce2 update index.html 2022-08-29 01:00:51 -04:00
idk
cd87569359 update EXAMPLE.html 2022-08-28 13:39:19 -04:00
idk
b0d86c9654 update DOCS.html 2022-08-28 13:39:16 -04:00
idk
d7f20533be update index.html 2022-08-28 13:39:08 -04:00
idk
3f39d265f7 update DESC.html 2022-08-28 13:39:03 -04:00
idk
962259e26c update index.html 2022-08-28 13:39:00 -04:00
idk
1ccf3ab24b Proxy convenience function 2022-08-26 00:03:17 -04:00
23 changed files with 1420 additions and 378 deletions

20
.github/workflows/auto-assign.yml vendored Normal file
View 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
View File

@@ -14,3 +14,6 @@
# Dependency directories (remove the comment below to include it)
# vendor/
data-dir*
i2pkeys/
onionkeys/
tlskeys/

View File

@@ -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
View File

@@ -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 &#34;i2pkeys&#34; 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 &#34;onionkeys&#34; 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 = &#34;127.0.0.1:7656&#34;
</code></pre>
<div>
<pre>var SAM_ADDR = &#34;127.0.0.1:7656&#34;
</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 structures keys
DialGarlic returns a net.Conn for a garlic structure&#39;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 structures keys
DialOnion returns a net.Conn for a onion structure&#39;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 &#34;.i2p&#34;, 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 structures keys
ListenGarlic returns a net.Listener for a garlic structure&#39;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 structures keys
ListenOnion returns a net.Listener for a onion structure&#39;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 structures sessions and listeners.
Close closes the Garlic structure&#39;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 structures I2P keys.
Dial returns a net.Conn for the Garlic structure&#39;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 structures I2P keys.
Listen returns a net.Listener for the Garlic structure&#39;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

View File

@@ -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 (
&#34;fmt&#34;
&#34;log&#34;
&#34;net/http&#34;
<span>import</span> <span>(</span>
<span>&#34;fmt&#34;</span>
<span>&#34;log&#34;</span>
<span>&#34;net/http&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
garlic := &amp;onramp.Garlic{}
defer garlic.Close()
listener, err := garlic.Listen()
if err != nil {
log.Fatal(err)
}
defer listener.Close()
http.HandleFunc(&#34;/&#34;, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, &#34;Hello, %q&#34;, 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>&amp;</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>&#34;/&#34;</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>&#34;Hello, %q&#34;</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 (
&#34;fmt&#34;
&#34;io/ioutil&#34;
&#34;log&#34;
&#34;net/http&#34;
<span>import</span> <span>(</span>
<span>&#34;fmt&#34;</span>
<span>&#34;io/ioutil&#34;</span>
<span>&#34;log&#34;</span>
<span>&#34;net/http&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
garlic := &amp;onramp.Garlic{}
defer garlic.Close()
transport := http.Transport{
Dial: garlic.Dial,
}
client := &amp;http.Client{
Transport: &amp;transport,
}
resp, err := client.Get(&#34;http://&#34; + listener.Addr().String() + &#34;/&#34;)
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>&amp;</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>&amp;</span><span>http</span><span>.</span><span>Client</span><span>{</span>
<span>Transport</span><span>:</span> <span>&amp;</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>&#34;http://&#34;</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>&#34;/&#34;</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 (
&#34;fmt&#34;
&#34;io/ioutil&#34;
&#34;log&#34;
&#34;net&#34;
&#34;net/http&#34;
)
<span>import</span> <span>(</span>
<span>&#34;fmt&#34;</span>
<span>&#34;io/ioutil&#34;</span>
<span>&#34;log&#34;</span>
<span>&#34;net&#34;</span>
<span>&#34;net/http&#34;</span>
<span>)</span>
func main() {
garlic := &amp;Garlic{}
defer garlic.Close()
listener, err := garlic.Listen()
if err != nil {
log.Fatal(err)
}
log.Println(&#34;listener:&#34;, listener.Addr().String())
defer listener.Close()
http.HandleFunc(&#34;/&#34;, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, &#34;Hello, %q&#34;, r.URL.Path)
})
go Serve(listener)
transport := http.Transport{
Dial: garlic.Dial,
}
client := &amp;http.Client{
Transport: &amp;transport,
}
resp, err := client.Get(&#34;http://&#34; + listener.Addr().String() + &#34;/&#34;)
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>&amp;</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>&#34;listener:&#34;</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>&#34;/&#34;</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>&#34;Hello, %q&#34;</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>&amp;</span><span>http</span><span>.</span><span>Client</span><span>{</span>
<span>Transport</span><span>:</span> <span>&amp;</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>&#34;http://&#34;</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>&#34;/&#34;</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 (
&#34;fmt&#34;
&#34;log&#34;
&#34;net/http&#34;
<span>import</span> <span>(</span>
<span>&#34;fmt&#34;</span>
<span>&#34;log&#34;</span>
<span>&#34;net/http&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
defer onramp.CloseAll()
listener, err := onramp.Listen(&#34;tcp&#34;, &#34;service.i2p&#34;)
if err != nil {
log.Fatal(err)
}
defer listener.Close()
http.HandleFunc(&#34;/&#34;, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, &#34;Hello, %q&#34;, 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>&#34;tcp&#34;</span><span>,</span> <span>&#34;service.i2p&#34;</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>&#34;/&#34;</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>&#34;Hello, %q&#34;</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 (
&#34;fmt&#34;
&#34;io/ioutil&#34;
&#34;log&#34;
&#34;net/http&#34;
<span>import</span> <span>(</span>
<span>&#34;fmt&#34;</span>
<span>&#34;io/ioutil&#34;</span>
<span>&#34;log&#34;</span>
<span>&#34;net/http&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
defer onramp.CloseAll()
transport := http.Transport{
Dial: onramp.Dial,
}
client := &amp;http.Client{
Transport: &amp;transport,
}
resp, err := client.Get(&#34;http://&#34; + listener.Addr().String() + &#34;/&#34;)
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>&amp;</span><span>http</span><span>.</span><span>Client</span><span>{</span>
<span>Transport</span><span>:</span> <span>&amp;</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>&#34;http://&#34;</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>&#34;/&#34;</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

View File

@@ -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
View 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 {} \;

View File

@@ -1,6 +1,8 @@
onramp
======
[![Go Report Card](https://goreportcard.com/badge/github.com/go-i2p/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.

View File

@@ -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
View File

@@ -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
View 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
)

View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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 URLs from Go.
High-level, easy-to-use listeners and clients for I2P and onion URL&#39;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 &#34;persistent&#34; 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 dont 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&#39;t want this behavior,
make sure to delete the &#34;keystore&#34; 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 youre ready to go.
a struct and you&#39;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 (
&#34;log&#34;
<span>import</span> <span>(</span>
<span>&#34;log&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
garlic := &amp;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>&amp;</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 (
&#34;log&#34;
<span>import</span> <span>(</span>
<span>&#34;log&#34;</span>
&#34;github.com/eyedeekay/onramp&#34;
)
<span>&#34;github.com/eyedeekay/onramp&#34;</span>
<span>)</span>
func main() {
onion := &amp;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>&amp;</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
View 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
View File

@@ -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
}

View File

@@ -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
View 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)
}

View File

@@ -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
View 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; }

View File

@@ -153,5 +153,5 @@ input {
#navbar {
float: right;
width: 10%;
width: 15%;
}

56
tls.go
View File

@@ -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})