Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
59fefebb3b | ||
![]() |
5fcf1a9ebd | ||
![]() |
d4bdf43bfe | ||
![]() |
c792d21e93 | ||
![]() |
48a91b87cb | ||
![]() |
4045bbb373 | ||
![]() |
a22f7d20d5 | ||
![]() |
66473209bd | ||
![]() |
7bffda6818 | ||
![]() |
73fe81d8d1 | ||
![]() |
a5c2783e8f | ||
![]() |
7eee870172 | ||
![]() |
c960f84603 | ||
![]() |
04475f172e | ||
![]() |
d9c72ac9ee | ||
![]() |
c63c6c659e | ||
![]() |
91ad6cf100 | ||
![]() |
6ff4194c85 | ||
![]() |
491b82d735 | ||
![]() |
a85762e2c7 | ||
![]() |
186e949cb0 | ||
![]() |
67698b4fa2 | ||
![]() |
666d4b3fc9 | ||
![]() |
07cbec85ee | ||
![]() |
0c960873e7 | ||
![]() |
8c414e2cc8 | ||
![]() |
c15d706a4e | ||
![]() |
c4bc115f49 | ||
![]() |
558e0208f1 | ||
![]() |
b5ef6cc54d | ||
![]() |
fe77d1c963 | ||
![]() |
a5eeda0549 | ||
![]() |
e1e0b15be9 | ||
![]() |
c5d6477825 | ||
![]() |
0560dd406c |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,2 +1,8 @@
|
||||
catbox
|
||||
*.swp
|
||||
/catbox
|
||||
/test-net
|
||||
*.crt
|
||||
*.crl
|
||||
*.pem
|
||||
terrarium
|
||||
terrarium.exe
|
||||
|
@@ -4,7 +4,6 @@ builds:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
- arm
|
||||
archive:
|
||||
wrap_in_directory: true
|
||||
files:
|
||||
|
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,7 +1,20 @@
|
||||
# 1.11.1
|
||||
# 1.14.0
|
||||
|
||||
* Stop publishing arm releases.
|
||||
* Support TLS 1.3.
|
||||
|
||||
|
||||
# 1.13.0 (2019-07-08)
|
||||
|
||||
* Include Go version in version string.
|
||||
|
||||
|
||||
# 1.12.0 (2019-07-06)
|
||||
|
||||
* Update dependencies.
|
||||
* Send messages during connect immediately rather than only after we've
|
||||
performed our reverse DNS lookup.
|
||||
* Stop logging client reads/writes.
|
||||
|
||||
|
||||
# 1.11.0 (2019-01-01)
|
||||
|
119
Makefile
Normal file
119
Makefile
Normal file
@@ -0,0 +1,119 @@
|
||||
VERSION=0.0.06
|
||||
CGO_ENABLED=0
|
||||
export CGO_ENABLED=0
|
||||
|
||||
GOOS?=$(shell uname -s | tr A-Z a-z)
|
||||
GOARCH?="amd64"
|
||||
|
||||
ARG=-v -tags netgo -ldflags '-w -extldflags "-static"'
|
||||
|
||||
BINARY=terrarium
|
||||
SIGNER=hankhill19580@gmail.com
|
||||
CONSOLEPOSTNAME=IRC
|
||||
USER_GH=eyedeekay
|
||||
|
||||
build: dep
|
||||
go build $(ARG) -tags="netgo" -o $(BINARY)-$(GOOS)-$(GOARCH) ./cmd/$(BINARY)
|
||||
make su3
|
||||
|
||||
clean:
|
||||
rm -f $(BINARY)-plugin plugin $(BINARY)-*zip -r
|
||||
rm -f *.su3 *.zip $(BINARY)-$(GOOS)-$(GOARCH) $(BINARY)-*
|
||||
|
||||
all: windows linux osx bsd
|
||||
|
||||
windows:
|
||||
GOOS=windows GOARCH=amd64 make build su3
|
||||
GOOS=windows GOARCH=386 make build su3
|
||||
|
||||
linux:
|
||||
GOOS=linux GOARCH=amd64 make build su3
|
||||
GOOS=linux GOARCH=arm64 make build su3
|
||||
GOOS=linux GOARCH=386 make build su3
|
||||
|
||||
osx:
|
||||
GOOS=darwin GOARCH=amd64 make build su3
|
||||
GOOS=darwin GOARCH=arm64 make build su3
|
||||
|
||||
bsd:
|
||||
GOOS=freebsd GOARCH=amd64 make build su3
|
||||
GOOS=openbsd GOARCH=amd64 make build su3
|
||||
|
||||
dep:
|
||||
cp "$(HOME)/Workspace/GIT_WORK/i2p.i2p/build/shellservice.jar" conf/lib/shellservice.jar -v
|
||||
|
||||
su3:
|
||||
i2p.plugin.native -name=$(BINARY)-$(GOOS)-$(GOARCH) \
|
||||
-signer=$(SIGNER) \
|
||||
-version "$(VERSION)" \
|
||||
-author=$(SIGNER) \
|
||||
-autostart=true \
|
||||
-clientname=$(BINARY)-$(GOOS)-$(GOARCH) \
|
||||
-consolename="$(BINARY) - $(CONSOLEPOSTNAME)" \
|
||||
-name="$(BINARY)-$(GOOS)-$(GOARCH)" \
|
||||
-delaystart="1" \
|
||||
-desc="`cat desc`" \
|
||||
-exename=$(BINARY)-$(GOOS)-$(GOARCH) \
|
||||
-icondata=icon/icon.png \
|
||||
-updateurl="http://idk.i2p/terrarium/$(BINARY)-$(GOOS)-$(GOARCH).su3" \
|
||||
-website="http://idk.i2p/terrarium/" \
|
||||
-command="$(BINARY)-$(GOOS)-$(GOARCH) -conf \"\$$PLUGIN/catbox-i2p.conf\"" \
|
||||
-license=MIT \
|
||||
-res=conf/
|
||||
unzip -o $(BINARY)-$(GOOS)-$(GOARCH).zip -d $(BINARY)-$(GOOS)-$(GOARCH)-zip
|
||||
|
||||
sum:
|
||||
sha256sum $(BINARY)-$(GOOS)-$(GOARCH).su3
|
||||
|
||||
version:
|
||||
gothub release -u eyedeekay -r terrarium -t "$(VERSION)" -d "`cat desc`"; true
|
||||
|
||||
upload:
|
||||
gothub upload -u eyedeekay -r terrarium -t "$(VERSION)" -f $(BINARY)-$(GOOS)-$(GOARCH).su3 -n $(BINARY)-$(GOOS)-$(GOARCH).su3 -l "`sha256sum $(BINARY)-$(GOOS)-$(GOARCH).su3`"
|
||||
|
||||
upload-windows:
|
||||
GOOS=windows GOARCH=amd64 make upload
|
||||
GOOS=windows GOARCH=386 make upload
|
||||
|
||||
upload-linux:
|
||||
GOOS=linux GOARCH=amd64 make upload
|
||||
GOOS=linux GOARCH=arm64 make upload
|
||||
GOOS=linux GOARCH=386 make upload
|
||||
|
||||
upload-osx:
|
||||
GOOS=darwin GOARCH=amd64 make upload
|
||||
GOOS=darwin GOARCH=arm64 make upload
|
||||
|
||||
upload-bsd:
|
||||
GOOS=freebsd GOARCH=amd64 make upload
|
||||
GOOS=openbsd GOARCH=amd64 make upload
|
||||
|
||||
upload-all: upload-windows upload-linux upload-osx upload-bsd
|
||||
|
||||
download-su3s:
|
||||
GOOS=windows GOARCH=amd64 make download-single-su3
|
||||
GOOS=windows GOARCH=386 make download-single-su3
|
||||
GOOS=linux GOARCH=amd64 make download-single-su3
|
||||
GOOS=linux GOARCH=arm64 make download-single-su3
|
||||
GOOS=linux GOARCH=386 make download-single-su3
|
||||
GOOS=darwin GOARCH=amd64 make download-single-su3
|
||||
GOOS=darwin GOARCH=arm64 make download-single-su3
|
||||
GOOS=freebsd GOARCH=amd64 make download-single-su3
|
||||
GOOS=openbsd GOARCH=amd64 make download-single-su3
|
||||
|
||||
download-single-su3:
|
||||
wget -N -c "https://github.com/$(USER_GH)/$(BINARY)/releases/download/$(VERSION)/$(BINARY)-$(GOOS)-$(GOARCH).su3"
|
||||
|
||||
release: clean all version upload-all
|
||||
|
||||
index:
|
||||
@echo "<!DOCTYPE html>" > index.html
|
||||
@echo "<html>" >> index.html
|
||||
@echo "<head>" >> index.html
|
||||
@echo " <title>$(BINARY) - $(CONSOLEPOSTNAME)</title>" >> index.html
|
||||
@echo " <link rel=\"stylesheet\" type=\"text/css\" href =\"/style.css\" />" >> index.html
|
||||
@echo "</head>" >> index.html
|
||||
@echo "<body>" >> index.html
|
||||
pandoc README.md >> index.html
|
||||
@echo "</body>" >> index.html
|
||||
@echo "</html>" >> index.html
|
72
README.md
72
README.md
@@ -1,12 +1,17 @@
|
||||

|
||||
# 
|
||||
|
||||
[](https://travis-ci.org/horgh/catbox)
|
||||
Status](https://travis-ci.org/eyedeekay/terrarium.svg)](https://travis-ci.org/eyedeekay/terrarium)
|
||||
[](https://goreportcard.com/report/github.com/horgh/catbox)
|
||||
Card](https://goreportcard.com/badge/i2pgit.org/idk/terrarium)](https://goreportcard.com/report/i2pgit.org/idk/terrarium)
|
||||
|
||||
catbox is an IRC server with a focus on being small and understandable. The
|
||||
goal is security.
|
||||
terrarium is an IRC server with a focus on being small and understandable,
|
||||
originally forked from [horgh/catbox](https://github.com/horgh/catbox). The
|
||||
goal is to create an easy-to-configure I2P IRC server which is highly stable
|
||||
and secure, while retaining the ability to link with non-I2P IRC servers using
|
||||
TLS in order to bridge anonymous and non-anonymous chat. For now, Bridged
|
||||
servers are not anonymous, this may change in the future as I evaluate the
|
||||
feasibility of outproxies or Tor.
|
||||
|
||||
|
||||
# Features
|
||||
@@ -17,24 +22,48 @@ goal is security.
|
||||
* K: line style connection banning
|
||||
* TLS
|
||||
|
||||
catbox implements enough of [RFC 1459](https://tools.ietf.org/html/rfc1459)
|
||||
to be recognisable as IRC and be minimally functional. I likely won't add
|
||||
much more and don't intend it to be complete. If I don't think something is
|
||||
required it likely won't be here.
|
||||
terrarium implements enough of [RFC 1459](https://tools.ietf.org/html/rfc1459)
|
||||
to be recognisable as IRC and be minimally functional. It will intentionally
|
||||
omit unnecessary features. Priority features are those which enable moderation
|
||||
and provide more flexible security.
|
||||
|
||||
# Plugin Installation URL's
|
||||
|
||||
[A guide to installing I2P plugins can be found on the I2P web site.](https://geti2p.net/en/docs/plugins)
|
||||
|
||||
### Inside I2P
|
||||
|
||||
- [Windows (In-I2P)](http://idk.i2p/terrarium/terrarium-windows-amd64.su3)
|
||||
- [Linux (In-I2P)](http://idk.i2p/terrarium/terrarium-linux-amd64.su3)
|
||||
|
||||
### Outside I2P
|
||||
|
||||
- [Windows](https://github.com/terrarium/blizzard/releases)
|
||||
- [Linux](https://github.com/terrarium/blizzard/releases)
|
||||
|
||||
# Installation
|
||||
1. Download catbox from the Releases tab on GitHub, or build from source
|
||||
1. Clone the software from [i2pgit.org](https://i2pgit.org/idk/terrarium)
|
||||
(`git clone https://i2pgit.org/idk/terrarium go/src/i2pgit.org/idk/terrarium && cd go/src/i2pgit.org/idk/terrarium`).
|
||||
2. Build from source
|
||||
(`go build`).
|
||||
2. Configure catbox through config files. There are example configs in the
|
||||
3. Configure terrarium through config files. There are example configs in the
|
||||
`conf` directory. All settings are optional and have defaults.
|
||||
3. Run it, e.g. `./catbox -conf catbox.conf`. I typically run catbox
|
||||
inside tmux using [this program](bin/tmux-run.sh).
|
||||
4. Run it, e.g. `./terrarium -conf terrarium.conf`. You might run it via systemd
|
||||
via a service such as:
|
||||
|
||||
```
|
||||
[Service]
|
||||
ExecStart=/home/ircd/terrarium/terrarium -conf /home/ircd/terrarium/terrarium.conf
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
|
||||
# Configuration
|
||||
|
||||
## catbox.conf
|
||||
## terrarium.conf
|
||||
Global server settings.
|
||||
|
||||
|
||||
@@ -64,10 +93,19 @@ Clients connect to the network hostname and verify against it. Servers
|
||||
connect to each other by server hostname and verify against it.
|
||||
|
||||
|
||||
## I2P
|
||||
An example I2P configuration can be found in:
|
||||
|
||||
`conf/catbox-i2p.conf`
|
||||
|
||||
That's all the docs I have for now
|
||||
|
||||
# Why the name?
|
||||
My domain name is summercat.com, cats love boxes, and a tribute to
|
||||
ircd-ratbox, the IRC daemon I used in the past.
|
||||
It was forked from an IRC server called catbox which had a focus on simplicity
|
||||
and understandability. It now has the ability to connect to other IRC servers
|
||||
through I2P Tunnels. Clearnet is to I2P Tunnels is sort of like Catbox is to
|
||||
Terrarium.
|
||||
|
||||
|
||||
# Logo
|
||||
catbox logo (c) 2017 Bee
|
||||
terrarium logo (c) 2017 Bee
|
||||
|
4
args.go
4
args.go
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"flag"
|
||||
@@ -13,7 +13,7 @@ type Args struct {
|
||||
ListenFD int
|
||||
}
|
||||
|
||||
func getArgs() *Args {
|
||||
func GetArgs() *Args {
|
||||
configFile := flag.String("conf", "", "Configuration file.")
|
||||
fd := flag.Int("listen-fd", -1,
|
||||
"File descriptor with listening port to use (optional).")
|
||||
|
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This is a way to run catbox in a tmux session.
|
||||
#
|
||||
# It runs in such a way as if catbox exits, the tmux window stays around so
|
||||
# that we can inspect catbox's recent output. This is useful for debugging.
|
||||
#
|
||||
# It would probably be better to run catbox via systemd or something, but I
|
||||
# don't want catbox's output to be logged anywhere. I only want recent output
|
||||
# to be accessible. Possibly systemd could be made to do that, but anyway.
|
||||
|
||||
set -e
|
||||
|
||||
tmux start-server
|
||||
tmux new-session -d -s catbox
|
||||
|
||||
tmux set-option -g set-remain-on-exit on
|
||||
tmux set-option -g history-limit 10000
|
||||
tmux set-option -g prefix2 C-a
|
||||
tmux set-option -g prefix C-a
|
||||
tmux bind-key C-a send-prefix
|
||||
tmux set-window-option -g mode-keys vi
|
||||
|
||||
tmux new-window /home/ircd/catbox/catbox -conf /home/ircd/catbox/catbox.conf
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import "github.com/horgh/irc"
|
||||
|
||||
|
55
cmd/terrarium/catbox.go
Normal file
55
cmd/terrarium/catbox.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"i2pgit.org/idk/terrarium"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Ldate | log.Ltime)
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
args := terrarium.GetArgs()
|
||||
if args == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
binPath, err := filepath.Abs(os.Args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to determine absolute path to binary: %s: %s",
|
||||
os.Args[0], err)
|
||||
}
|
||||
|
||||
cb, err := terrarium.NewCatbox(args.ConfigFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cb.Start(args.ListenFD); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if cb.Restart {
|
||||
log.Printf("Shutdown completed. Restarting...")
|
||||
|
||||
if err := syscall.Exec( // nolint: gas
|
||||
binPath,
|
||||
[]string{
|
||||
binPath,
|
||||
"-conf",
|
||||
cb.ConfigFile,
|
||||
},
|
||||
nil,
|
||||
); err != nil {
|
||||
log.Fatalf("Restart failed: %s", err)
|
||||
}
|
||||
|
||||
log.Fatalf("not reached")
|
||||
}
|
||||
|
||||
log.Printf("Server shutdown cleanly.")
|
||||
}
|
61
conf/catbox-i2p.conf
Normal file
61
conf/catbox-i2p.conf
Normal file
@@ -0,0 +1,61 @@
|
||||
# The main terrarium config.
|
||||
#
|
||||
# The commented options are the defaults which are used if you do not specify
|
||||
# the option.
|
||||
|
||||
# Host to listen on.
|
||||
listen-host = 127.0.0.1
|
||||
|
||||
# Port to listen on. Set -1 to not listen.
|
||||
listen-port = 7667
|
||||
|
||||
# Port to listen on (TLS). Set -1 to not listen.
|
||||
listen-port-tls = -1
|
||||
|
||||
listen-i2p = terrarium.i2p
|
||||
sam-address = 127.0.0.1:7656
|
||||
|
||||
# File containing server certificate for TLS. PEM encoded.
|
||||
# Must be set if you have a TLS listen port.
|
||||
#certificate-file =
|
||||
|
||||
# File containing server key for TLS. PEM encoded.
|
||||
# Must be set if you have a TLS listen port.
|
||||
#key-file =
|
||||
|
||||
# Name server goes by.
|
||||
server-name = irc.terrarium.i2p
|
||||
|
||||
# Short info line (shown in WHOIS).
|
||||
#server-info = IRC
|
||||
|
||||
# MOTD. Only one line at this time.
|
||||
#motd = Hello this is terrarium
|
||||
|
||||
# Maximum nick length. RFCs say 9, but longer is okay.
|
||||
#max-nick-length = 9
|
||||
|
||||
# Maximum period of time a client can be idle before we ping it.
|
||||
#ping-time = 30s
|
||||
|
||||
# Maximum period of time a client can be idle before we consider it dead.
|
||||
#dead-time = 240s
|
||||
|
||||
# Time to wait between attempts connecting to servers (minimum).
|
||||
#connect-attempt-time = 60s
|
||||
|
||||
# TS6 SID. Must be unique in the network. Format: [0-9][A-Z0-9]{2}
|
||||
#ts6-sid = 000
|
||||
|
||||
# Administrator's email. It gets displayed in some errors.
|
||||
#admin-email =
|
||||
|
||||
# Path to opers configuration. This defines server operators.
|
||||
#opers-config =
|
||||
|
||||
# Path to servers configuration. This defines servers to link with.
|
||||
#servers-config =
|
||||
|
||||
# Path to the users configuration. This defines spoofs and whether users are
|
||||
# exempt from flood protection.
|
||||
#users-config =
|
@@ -1,4 +1,4 @@
|
||||
# The main catbox config.
|
||||
# The main terrarium config.
|
||||
#
|
||||
# The commented options are the defaults which are used if you do not specify
|
||||
# the option.
|
||||
@@ -27,7 +27,7 @@
|
||||
#server-info = IRC
|
||||
|
||||
# MOTD. Only one line at this time.
|
||||
#motd = Hello this is catbox
|
||||
#motd = Hello this is terrarium
|
||||
|
||||
# Maximum nick length. RFCs say 9, but longer is okay.
|
||||
#max-nick-length = 9
|
||||
|
24
config.go
24
config.go
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -18,6 +18,11 @@ type Config struct {
|
||||
KeyFile string
|
||||
ServerName string
|
||||
|
||||
// Listen on Hidden Service addresses
|
||||
ListenI2P string
|
||||
ListenI2PTLS string
|
||||
SAMAddress string
|
||||
|
||||
// Description of server. This shows in WHOIS, etc.
|
||||
ServerInfo string
|
||||
|
||||
@@ -101,6 +106,21 @@ func checkAndParseConfig(file string) (*Config, error) {
|
||||
c.ListenPortTLS = m["listen-port-tls"]
|
||||
}
|
||||
|
||||
c.ListenI2P = "-1"
|
||||
if m["listen-i2p"] != "" {
|
||||
c.ListenI2P = m["listen-i2p"]
|
||||
}
|
||||
|
||||
c.ListenI2PTLS = "-1"
|
||||
if m["listen-i2p-tls"] != "" {
|
||||
c.ListenI2PTLS = m["listen-i2p-tls"]
|
||||
}
|
||||
|
||||
c.SAMAddress = "127.0.0.1:7656"
|
||||
if m["sam-address"] != "" {
|
||||
c.SAMAddress = m["sam-address"]
|
||||
}
|
||||
|
||||
if m["certificate-file"] != "" {
|
||||
c.CertificateFile = m["certificate-file"]
|
||||
}
|
||||
@@ -119,7 +139,7 @@ func checkAndParseConfig(file string) (*Config, error) {
|
||||
c.ServerInfo = m["server-info"]
|
||||
}
|
||||
|
||||
c.MOTD = "Hello this is catbox"
|
||||
c.MOTD = "Hello this is terrarium"
|
||||
if m["motd"] != "" {
|
||||
c.MOTD = m["motd"]
|
||||
}
|
||||
|
5
desc
Normal file
5
desc
Normal file
@@ -0,0 +1,5 @@
|
||||
terrarium is an IRC server with a focus on being small and understandable,
|
||||
originally forked from [horgh/catbox](https://github.com/horgh/catbox). The
|
||||
goal is to create an easy-to-configure I2P IRC server which is highly stable
|
||||
and secure, while retaining the ability to link with non-I2P IRC servers using
|
||||
TLS in order to bridge anonymous and non-anonymous chat.
|
12
go.mod
12
go.mod
@@ -1,9 +1,15 @@
|
||||
module github.com/horgh/catbox
|
||||
module i2pgit.org/idk/terrarium
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/eyedeekay/sam3 v0.32.32
|
||||
github.com/horgh/config v0.0.0-20190101204049-770bc48a3bdf
|
||||
github.com/horgh/irc v0.0.0-20190101204118-d089b0b5b5c5
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
28
go.sum
28
go.sum
@@ -1,28 +1,28 @@
|
||||
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/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/horgh/config v0.0.0-20180303191532-3d1f920eb228 h1:R302KZFIBabAYgFZ0hgqRTeCF43Lm5rir+UnJYW3idQ=
|
||||
github.com/horgh/config v0.0.0-20180303191532-3d1f920eb228/go.mod h1:DSwQKBmwAzGuDhYajjeJshx5PCPCJfSZJXtbV+8/nck=
|
||||
github.com/horgh/config v0.0.0-20190101202014-d9e8eabe6dbb h1:u6pj1d0h6XSjJ84iixIMvSZT1fbLC1g4qqkV54EMOfo=
|
||||
github.com/horgh/config v0.0.0-20190101202014-d9e8eabe6dbb/go.mod h1:DSwQKBmwAzGuDhYajjeJshx5PCPCJfSZJXtbV+8/nck=
|
||||
github.com/eyedeekay/sam3 v0.32.32 h1:9Ea1Ere5O8Clx8zYxKnvhrWy7R96Q4FvxlPskYf8VW0=
|
||||
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
||||
github.com/horgh/config v0.0.0-20190101204049-770bc48a3bdf h1:/jDikK0Oteboi7/Z6uzan5aQhiqwMwKTIA+5ZooDclk=
|
||||
github.com/horgh/config v0.0.0-20190101204049-770bc48a3bdf/go.mod h1:DSwQKBmwAzGuDhYajjeJshx5PCPCJfSZJXtbV+8/nck=
|
||||
github.com/horgh/irc v0.0.0-20180101050313-f421bdb90dcc h1:FXH8Jqdcz9BbR94qHrCVGA5FhbcWNC+HpIXYwVgOc2I=
|
||||
github.com/horgh/irc v0.0.0-20180101050313-f421bdb90dcc/go.mod h1:UqEB9NVUSZzN4ESuQX3yEvi80Mgg2O4kttl8oU9+nds=
|
||||
github.com/horgh/irc v0.0.0-20190101203129-f09ebee6408d h1:ANDjU4bIeLO80xssAxig8qftG6ohyg08IqsIPnKqafg=
|
||||
github.com/horgh/irc v0.0.0-20190101203129-f09ebee6408d/go.mod h1:JLhFcwXOnpvhMer1MERfJuFIoJnADayDWe0VkMN3LP4=
|
||||
github.com/horgh/irc v0.0.0-20190101204118-d089b0b5b5c5 h1:wndND79llNLTZZW/Xcg9oKMk/NuGMo+pAX+LKg1mZF8=
|
||||
github.com/horgh/irc v0.0.0-20190101204118-d089b0b5b5c5/go.mod h1:JLhFcwXOnpvhMer1MERfJuFIoJnADayDWe0VkMN3LP4=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
73
index.html
Normal file
73
index.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>terrarium - IRC</title>
|
||||
<link rel="stylesheet" type="text/css" href ="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="terrarium"><img src="doc/terrarium-with-text.png" alt="terrarium" /></h1>
|
||||
<p><a href="https://travis-ci.org/eyedeekay/terrarium"><img src="https://travis-ci.org/eyedeekay/terrarium.svg" alt="Build Status" /></a> <a href="https://goreportcard.com/report/i2pgit.org/idk/terrarium"><img src="https://goreportcard.com/badge/i2pgit.org/idk/terrarium" alt="Go Report Card" /></a></p>
|
||||
<p>terrarium is an IRC server with a focus on being small and understandable, originally forked from <a href="https://github.com/horgh/catbox">horgh/catbox</a>. The goal is to create an easy-to-configure I2P IRC server which is highly stable and secure, while retaining the ability to link with non-I2P IRC servers using TLS in order to bridge anonymous and non-anonymous chat. For now, Bridged servers are not anonymous, this may change in the future as I evaluate the feasibility of outproxies or Tor.</p>
|
||||
<h1 id="features">Features</h1>
|
||||
<ul>
|
||||
<li>Server to server linking</li>
|
||||
<li>IRC operators</li>
|
||||
<li>Private (WHOIS shows no channels, LIST isn’t supported)</li>
|
||||
<li>Flood protection</li>
|
||||
<li>K: line style connection banning</li>
|
||||
<li>TLS</li>
|
||||
</ul>
|
||||
<p>terrarium implements enough of <a href="https://tools.ietf.org/html/rfc1459">RFC 1459</a> to be recognisable as IRC and be minimally functional. It will intentionally omit unnecessary features. Priority features are those which enable moderation and provide more flexible security.</p>
|
||||
<h1 id="plugin-installation-urls">Plugin Installation URL’s</h1>
|
||||
<p><a href="https://geti2p.net/en/docs/plugins">A guide to installing I2P plugins can be found on the I2P web site.</a></p>
|
||||
<h3 id="inside-i2p">Inside I2P</h3>
|
||||
<ul>
|
||||
<li><a href="http://idk.i2p/terrarium/terrarium-windows-amd64.su3">Windows (In-I2P)</a></li>
|
||||
<li><a href="http://idk.i2p/terrarium/terrarium-linux-amd64.su3">Linux (In-I2P)</a></li>
|
||||
</ul>
|
||||
<h3 id="outside-i2p">Outside I2P</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/terrarium/blizzard/releases">Windows</a></li>
|
||||
<li><a href="https://github.com/terrarium/blizzard/releases">Linux</a></li>
|
||||
</ul>
|
||||
<h1 id="installation">Installation</h1>
|
||||
<ol type="1">
|
||||
<li>Clone the software from <a href="https://i2pgit.org/idk/terrarium">i2pgit.org</a> (<code>git clone https://i2pgit.org/idk/terrarium go/src/i2pgit.org/idk/terrarium && cd go/src/i2pgit.org/idk/terrarium</code>).</li>
|
||||
<li>Build from source (<code>go build</code>).</li>
|
||||
<li>Configure terrarium through config files. There are example configs in the <code>conf</code> directory. All settings are optional and have defaults.</li>
|
||||
<li>Run it, e.g. <code>./terrarium -conf terrarium.conf</code>. You might run it via systemd via a service such as:</li>
|
||||
</ol>
|
||||
<pre><code>[Service]
|
||||
ExecStart=/home/ircd/terrarium/terrarium -conf /home/ircd/terrarium/terrarium.conf
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target</code></pre>
|
||||
<h1 id="configuration">Configuration</h1>
|
||||
<h2 id="terrarium.conf">terrarium.conf</h2>
|
||||
<p>Global server settings.</p>
|
||||
<h2 id="opers.conf">opers.conf</h2>
|
||||
<p>IRC operators.</p>
|
||||
<h2 id="servers.conf">servers.conf</h2>
|
||||
<p>The servers to link with.</p>
|
||||
<h2 id="users.conf">users.conf</h2>
|
||||
<p>Privileges and hostname spoofs for users.</p>
|
||||
<p>The only privilege right now is flood exemption.</p>
|
||||
<h2 id="tls">TLS</h2>
|
||||
<p>A setup for a network might look like this:</p>
|
||||
<ul>
|
||||
<li>Give each server a certificate with 2 SANs: Its own hostname, e.g. server1.example.com, and the network hostname, e.g. irc.example.com.</li>
|
||||
<li>Set up irc.example.com with DNS round-robin listing each server’s IP.</li>
|
||||
<li>List each server by its own hostname in servers.conf.</li>
|
||||
</ul>
|
||||
<p>Clients connect to the network hostname and verify against it. Servers connect to each other by server hostname and verify against it.</p>
|
||||
<h2 id="i2p">I2P</h2>
|
||||
<p>An example I2P configuration can be found in:</p>
|
||||
<p><code>conf/catbox-i2p.conf</code></p>
|
||||
<p>That’s all the docs I have for now</p>
|
||||
<h1 id="why-the-name">Why the name?</h1>
|
||||
<p>It was forked from an IRC server called catbox which had a focus on simplicity and understandability. It now has the ability to connect to other IRC servers through I2P Tunnels. Clearnet is to I2P Tunnels is sort of like Catbox is to Terrarium.</p>
|
||||
<h1 id="logo">Logo</h1>
|
||||
<p>terrarium logo (c) 2017 Bee</p>
|
||||
</body>
|
||||
</html>
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
@@ -176,8 +176,6 @@ func (c *LocalClient) readLoop() {
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Client %s: Read: %s", c, strings.TrimSuffix(buf, "\r\n"))
|
||||
|
||||
message, err := irc.ParseMessage(buf)
|
||||
if err != nil {
|
||||
c.Catbox.noticeOpers(fmt.Sprintf("Invalid message from client %s: %s", c,
|
||||
@@ -249,8 +247,6 @@ Loop:
|
||||
c.Catbox.newEvent(Event{Type: DeadClientEvent, Client: c, Error: err})
|
||||
break Loop
|
||||
}
|
||||
|
||||
log.Printf("Client %s: Sent: %s", c, strings.TrimSuffix(buf, "\r\n"))
|
||||
case <-c.Catbox.ShutdownChan:
|
||||
break Loop
|
||||
}
|
||||
@@ -383,7 +379,8 @@ func (c *LocalClient) registerUser() {
|
||||
lu.messageFromServer("002", []string{
|
||||
fmt.Sprintf("Your host is %s, running version %s",
|
||||
lu.Catbox.Config.ServerName,
|
||||
Version),
|
||||
lu.Catbox.version(),
|
||||
),
|
||||
})
|
||||
|
||||
// 003 RPL_CREATED
|
||||
@@ -396,7 +393,7 @@ func (c *LocalClient) registerUser() {
|
||||
lu.messageFromServer("004", []string{
|
||||
// It seems ambiguous if these are to be separate parameters.
|
||||
lu.Catbox.Config.ServerName,
|
||||
Version,
|
||||
lu.Catbox.version(),
|
||||
// User modes we support.
|
||||
"ioC",
|
||||
// Channel modes we support.
|
||||
@@ -433,13 +430,13 @@ func (c *LocalClient) registerUser() {
|
||||
})
|
||||
|
||||
// Send a CLICONN message. This is a custom command I built into ratbox
|
||||
// so that local opers can know about remote connections. For catbox we
|
||||
// so that local opers can know about remote connections. For terrarium we
|
||||
// don't need to handle this to know about remote connections as I inform
|
||||
// local operators about remote users connecting in the UID command, but to
|
||||
// allow my ratbox servers to know about connections to ratbox, send CLICONN
|
||||
// (for now). If I ever stop running all ratbox servers on my network, this
|
||||
// can be removed.
|
||||
// catbox should propagate this command though.
|
||||
// terrarium should propagate this command though.
|
||||
server.maybeQueueMessage(irc.Message{
|
||||
Prefix: string(u.UID),
|
||||
Command: "CLICONN",
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -2094,8 +2094,6 @@ func (u *LocalUser) versionCommand(m irc.Message) {
|
||||
// Comments are free form. But I use similar to what ratbox does. See its doc
|
||||
// server-version-info.
|
||||
|
||||
version := fmt.Sprintf("%s.", Version)
|
||||
|
||||
// H HUB, M IDLE_FROM_MSG, TS supports TS, 6 TS6, o TS only
|
||||
comments := fmt.Sprintf("HM TS6o %s", string(u.Catbox.Config.TS6SID))
|
||||
|
||||
@@ -2104,7 +2102,7 @@ func (u *LocalUser) versionCommand(m irc.Message) {
|
||||
Command: "351",
|
||||
Params: []string{
|
||||
u.User.DisplayNick,
|
||||
version,
|
||||
u.Catbox.version(),
|
||||
u.Catbox.Config.ServerName,
|
||||
comments,
|
||||
},
|
||||
|
155
main.go
155
main.go
@@ -1,14 +1,16 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -16,6 +18,8 @@ import (
|
||||
|
||||
"github.com/horgh/irc"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
sam "github.com/eyedeekay/sam3/helper"
|
||||
)
|
||||
|
||||
// Catbox holds the state for this local server.
|
||||
@@ -94,6 +98,10 @@ type Catbox struct {
|
||||
Listener net.Listener
|
||||
TLSListener net.Listener
|
||||
|
||||
// I2P Streaming and I2P+TLS listeners.
|
||||
I2PListener net.Listener
|
||||
I2PListenerTLS net.Listener
|
||||
|
||||
// WaitGroup to ensure all goroutines clean up before we end.
|
||||
WG sync.WaitGroup
|
||||
|
||||
@@ -197,52 +205,18 @@ const ExcessFloodThreshold = 50
|
||||
// from a user.
|
||||
const ChanModesPerCommand = 4
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Ldate | log.Ltime)
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
args := getArgs()
|
||||
if args == nil {
|
||||
os.Exit(1)
|
||||
func randString() string {
|
||||
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
n := 3
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
||||
}
|
||||
|
||||
binPath, err := filepath.Abs(os.Args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to determine absolute path to binary: %s: %s",
|
||||
os.Args[0], err)
|
||||
}
|
||||
|
||||
cb, err := newCatbox(args.ConfigFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cb.start(args.ListenFD); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if cb.Restart {
|
||||
log.Printf("Shutdown completed. Restarting...")
|
||||
|
||||
if err := syscall.Exec( // nolint: gas
|
||||
binPath,
|
||||
[]string{
|
||||
binPath,
|
||||
"-conf",
|
||||
cb.ConfigFile,
|
||||
},
|
||||
nil,
|
||||
); err != nil {
|
||||
log.Fatalf("Restart failed: %s", err)
|
||||
}
|
||||
|
||||
log.Fatalf("not reached")
|
||||
}
|
||||
|
||||
log.Printf("Server shutdown cleanly.")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func newCatbox(configFile string) (*Catbox, error) {
|
||||
func NewCatbox(configFile string) (*Catbox, error) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
cb := Catbox{
|
||||
ConfigFile: configFile,
|
||||
LocalClients: make(map[uint64]*LocalClient),
|
||||
@@ -266,6 +240,9 @@ func newCatbox(configFile string) (*Catbox, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("configuration problem: %s", err)
|
||||
}
|
||||
if cfg.ServerName == "irc.terrarium.i2p" {
|
||||
cfg.ServerName = randString() + ".dirt.i2p"
|
||||
}
|
||||
cb.Config = cfg
|
||||
|
||||
if cb.Config.ListenPortTLS != "-1" || cb.Config.CertificateFile != "" ||
|
||||
@@ -327,7 +304,7 @@ func (cb *Catbox) loadCertificate() error {
|
||||
//
|
||||
// We open the TCP port, start goroutines, and then receive messages on our
|
||||
// channels.
|
||||
func (cb *Catbox) start(listenFD int) error {
|
||||
func (cb *Catbox) Start(listenFD int) error {
|
||||
if listenFD == -1 && cb.Config.ListenPort == "-1" &&
|
||||
cb.Config.ListenPortTLS == "-1" {
|
||||
log.Fatalf("You must set a listen port.")
|
||||
@@ -372,6 +349,49 @@ func (cb *Catbox) start(listenFD int) error {
|
||||
go cb.acceptConnections(cb.TLSListener)
|
||||
}
|
||||
|
||||
// I2P Listener
|
||||
if cb.Config.ListenI2P != "-1" {
|
||||
ln, err := sam.I2PListener(cb.Config.ListenI2P, cb.Config.SAMAddress, cb.Config.ListenI2P)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to listen (I2P): %s", err)
|
||||
}
|
||||
cb.I2PListener = ln
|
||||
err = ioutil.WriteFile(cb.Config.ListenI2P+".i2paddresshelper", []byte("http://"+cb.Config.ListenI2P+"/?i2paddresshelper="+cb.I2PListener.Addr().String()), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write I2P addresshelper link to file: %s", err)
|
||||
}
|
||||
if strings.HasSuffix(cb.Config.ServerName, ".i2p") {
|
||||
err = ioutil.WriteFile(cb.Config.ServerName+".i2paddresshelper", []byte("http://"+cb.Config.ServerName+"/?i2paddresshelper="+cb.I2PListener.Addr().String()), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write I2P addresshelper link to file: %s", err)
|
||||
}
|
||||
}
|
||||
cb.WG.Add(1)
|
||||
go cb.acceptConnections(cb.Listener)
|
||||
}
|
||||
|
||||
// I2P Listener with TLS
|
||||
if cb.Config.ListenI2PTLS != "-1" {
|
||||
ln, err := sam.I2PListener(cb.Config.ListenI2PTLS, cb.Config.SAMAddress, cb.Config.ListenI2PTLS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to listen (I2P): %s", err)
|
||||
}
|
||||
tlsln := tls.NewListener(ln, cb.TLSConfig)
|
||||
cb.I2PListenerTLS = tlsln
|
||||
err = ioutil.WriteFile(cb.Config.ListenI2PTLS+".tls.i2paddresshelper", []byte("http://"+cb.Config.ListenI2PTLS+"?i2paddresshelper="+cb.I2PListener.Addr().String()), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write I2P addresshelper link to file: %s", err)
|
||||
}
|
||||
if strings.HasSuffix(cb.Config.ServerName, ".i2p") {
|
||||
err = ioutil.WriteFile(cb.Config.ServerName+".tls.i2paddresshelper", []byte("http://"+cb.Config.ServerName+"?i2paddresshelper="+cb.I2PListener.Addr().String()), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write I2P addresshelper link to file: %s", err)
|
||||
}
|
||||
}
|
||||
cb.WG.Add(1)
|
||||
go cb.acceptConnections(cb.Listener)
|
||||
}
|
||||
|
||||
// Alarm is a goroutine to wake up this one periodically so we can do things
|
||||
// like ping clients.
|
||||
cb.WG.Add(1)
|
||||
@@ -381,7 +401,7 @@ func (cb *Catbox) start(listenFD int) error {
|
||||
// Catch SIGUSR1 and restart.
|
||||
signalChan := make(chan os.Signal)
|
||||
signal.Notify(signalChan, syscall.SIGHUP)
|
||||
signal.Notify(signalChan, syscall.SIGUSR1)
|
||||
signal.Notify(signalChan, syscall.SIGINT)
|
||||
|
||||
cb.WG.Add(1)
|
||||
go func() {
|
||||
@@ -394,7 +414,7 @@ func (cb *Catbox) start(listenFD int) error {
|
||||
cb.newEvent(Event{Type: RehashEvent})
|
||||
break
|
||||
}
|
||||
if sig == syscall.SIGUSR1 {
|
||||
if sig == syscall.SIGINT {
|
||||
log.Printf("Received SIGUSR1 signal, restarting")
|
||||
cb.newEvent(Event{Type: RestartEvent})
|
||||
break
|
||||
@@ -413,7 +433,7 @@ func (cb *Catbox) start(listenFD int) error {
|
||||
}
|
||||
}()
|
||||
|
||||
log.Printf("catbox started")
|
||||
log.Printf("terrarium started")
|
||||
cb.eventLoop()
|
||||
|
||||
// We don't need to drain any channels. None close that will have any
|
||||
@@ -649,7 +669,7 @@ func (cb *Catbox) introduceClient(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
if tlsVersion != "TLS 1.2" {
|
||||
if tlsVersion != "TLS 1.2" && tlsVersion != "TLS 1.3" {
|
||||
cb.noticeOpers(fmt.Sprintf("Rejecting client %s using %s",
|
||||
client.Conn.IP, tlsVersion))
|
||||
// Send ERROR and start up the writer to try to let them get it. Don't
|
||||
@@ -996,13 +1016,34 @@ func (cb *Catbox) connectToServer(linkInfo *ServerDefinition) {
|
||||
var err error
|
||||
|
||||
if linkInfo.TLS {
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s with TLS...", linkInfo.Name))
|
||||
if strings.HasSuffix(linkInfo.Hostname, ".i2p") {
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s with I2P and TLS...", linkInfo.Name))
|
||||
|
||||
dialer := &net.Dialer{
|
||||
Timeout: cb.Config.DeadTime,
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s with I2P...",
|
||||
linkInfo.Name))
|
||||
I2PSession, err := sam.I2PStreamSession(cb.Config.ListenI2P+"-tls-"+linkInfo.Hostname, cb.Config.SAMAddress, cb.Config.ListenI2P+"-tls-"+linkInfo.Hostname)
|
||||
if err == nil {
|
||||
conn, err = I2PSession.Dial("tcp", linkInfo.Hostname)
|
||||
if err == nil {
|
||||
conn = tls.Client(conn, cb.TLSConfig)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s with TLS...", linkInfo.Name))
|
||||
|
||||
dialer := &net.Dialer{
|
||||
Timeout: cb.Config.DeadTime,
|
||||
}
|
||||
conn, err = tls.DialWithDialer(dialer, "tcp",
|
||||
fmt.Sprintf("%s:%d", linkInfo.Hostname, linkInfo.Port), cb.TLSConfig)
|
||||
}
|
||||
} else if strings.HasSuffix(linkInfo.Hostname, ".i2p") {
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s with I2P...",
|
||||
linkInfo.Name))
|
||||
I2PSession, err := sam.I2PStreamSession(cb.Config.ListenI2P+"-"+linkInfo.Hostname, cb.Config.SAMAddress, cb.Config.ListenI2P+"-"+linkInfo.Hostname)
|
||||
if err == nil {
|
||||
conn, err = I2PSession.Dial("tcp", linkInfo.Hostname)
|
||||
}
|
||||
conn, err = tls.DialWithDialer(dialer, "tcp",
|
||||
fmt.Sprintf("%s:%d", linkInfo.Hostname, linkInfo.Port), cb.TLSConfig)
|
||||
} else {
|
||||
cb.noticeOpers(fmt.Sprintf("Connecting to %s without TLS...",
|
||||
linkInfo.Name))
|
||||
@@ -1029,7 +1070,7 @@ func (cb *Catbox) connectToServer(linkInfo *ServerDefinition) {
|
||||
return
|
||||
}
|
||||
|
||||
if tlsVersion != "TLS 1.2" {
|
||||
if tlsVersion != "TLS 1.2" && tlsVersion != "TLS 1.3" {
|
||||
cb.noticeOpers(fmt.Sprintf(
|
||||
"Disconnecting from %s because of TLS version: %s", linkInfo.Name,
|
||||
tlsVersion))
|
||||
@@ -1705,3 +1746,5 @@ func sendMessages(messages []Message) {
|
||||
m.Target.maybeQueueMessage(m.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func (cb *Catbox) version() string { return Version + "-" + runtime.Version() }
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Catbox holds information about a harnessed catbox.
|
||||
// Catbox holds information about a harnessed terrarium.
|
||||
type Catbox struct {
|
||||
Name string
|
||||
SID string
|
||||
@@ -33,19 +33,19 @@ type Catbox struct {
|
||||
LogChan <-chan string
|
||||
}
|
||||
|
||||
const catboxDir = ".."
|
||||
const terrariumDir = ".."
|
||||
|
||||
func harnessCatbox(
|
||||
name,
|
||||
sid string,
|
||||
) (*Catbox, error) {
|
||||
if err := buildCatbox(); err != nil {
|
||||
return nil, fmt.Errorf("error building catbox: %s", err)
|
||||
return nil, fmt.Errorf("error building terrarium: %s", err)
|
||||
}
|
||||
|
||||
catbox, err := startCatbox(name, sid)
|
||||
terrarium, err := startCatbox(name, sid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error starting catbox: %s", err)
|
||||
return nil, fmt.Errorf("error starting terrarium: %s", err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
@@ -53,34 +53,34 @@ func harnessCatbox(
|
||||
logChan := make(chan string, 1024)
|
||||
|
||||
wg.Add(1)
|
||||
go logReader(&wg, fmt.Sprintf("%s stderr", name), catbox.Stderr, logChan)
|
||||
go logReader(&wg, fmt.Sprintf("%s stderr", name), terrarium.Stderr, logChan)
|
||||
|
||||
wg.Add(1)
|
||||
go logReader(&wg, fmt.Sprintf("%s stdout", name), catbox.Stdout, logChan)
|
||||
go logReader(&wg, fmt.Sprintf("%s stdout", name), terrarium.Stdout, logChan)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := catbox.Command.Wait(); err != nil {
|
||||
log.Printf("catbox exited: %s", err)
|
||||
if err := terrarium.Command.Wait(); err != nil {
|
||||
log.Printf("terrarium exited: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
catbox.WaitGroup = &wg
|
||||
catbox.LogChan = logChan
|
||||
terrarium.WaitGroup = &wg
|
||||
terrarium.LogChan = logChan
|
||||
|
||||
// It is important to wait for catbox to fully start. If we don't, then
|
||||
// It is important to wait for terrarium to fully start. If we don't, then
|
||||
// certain things we do in tests will not work well. For example, trying to
|
||||
// reload the conf by sending a SIGHUP will kill the process.
|
||||
startedRE := regexp.MustCompile(
|
||||
`^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} catbox started$`)
|
||||
`^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} terrarium started$`)
|
||||
|
||||
if !waitForLog(logChan, startedRE) {
|
||||
catbox.stop()
|
||||
return nil, fmt.Errorf("error waiting for catbox to start")
|
||||
terrarium.stop()
|
||||
return nil, fmt.Errorf("error waiting for terrarium to start")
|
||||
}
|
||||
|
||||
return catbox, nil
|
||||
return terrarium, nil
|
||||
}
|
||||
|
||||
var builtCatbox bool
|
||||
@@ -91,12 +91,12 @@ func buildCatbox() error {
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "build")
|
||||
cmd.Dir = catboxDir
|
||||
cmd.Dir = terrariumDir
|
||||
|
||||
log.Printf("Running %s in [%s]...", cmd.Args, cmd.Dir)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building catbox: %s: %s", err, output)
|
||||
return fmt.Errorf("error building terrarium: %s: %s", err, output)
|
||||
}
|
||||
|
||||
builtCatbox = true
|
||||
@@ -112,7 +112,7 @@ func startCatbox(
|
||||
return nil, fmt.Errorf("error retrieving a temporary directory: %s", err)
|
||||
}
|
||||
|
||||
catboxConf := filepath.Join(tmpDir, "catbox.conf")
|
||||
terrariumConf := filepath.Join(tmpDir, "terrarium.conf")
|
||||
|
||||
listener, port, err := getRandomPort()
|
||||
if err != nil {
|
||||
@@ -120,15 +120,15 @@ func startCatbox(
|
||||
return nil, fmt.Errorf("error opening random port: %s", err)
|
||||
}
|
||||
|
||||
catbox, err := runCatbox(catboxConf, listener, port, name, sid)
|
||||
terrarium, err := runCatbox(terrariumConf, listener, port, name, sid)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
_ = listener.Close()
|
||||
return nil, fmt.Errorf("error running catbox: %s", err)
|
||||
return nil, fmt.Errorf("error running terrarium: %s", err)
|
||||
}
|
||||
|
||||
catbox.ConfigDir = tmpDir
|
||||
return catbox, nil
|
||||
terrarium.ConfigDir = tmpDir
|
||||
return terrarium, nil
|
||||
}
|
||||
|
||||
func getRandomPort() (net.Listener, uint16, error) {
|
||||
@@ -161,12 +161,12 @@ func runCatbox(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command("./catbox",
|
||||
cmd := exec.Command("./terrarium",
|
||||
"-conf", conf,
|
||||
"-listen-fd", "3",
|
||||
)
|
||||
|
||||
cmd.Dir = catboxDir
|
||||
cmd.Dir = terrariumDir
|
||||
|
||||
f, err := ln.(*net.TCPListener).File()
|
||||
if err != nil {
|
||||
@@ -257,7 +257,7 @@ func logReader(
|
||||
|
||||
func (c *Catbox) stop() {
|
||||
if err := c.Command.Process.Kill(); err != nil {
|
||||
log.Printf("error killing catbox: %s", err)
|
||||
log.Printf("error killing terrarium: %s", err)
|
||||
}
|
||||
c.WaitGroup.Wait()
|
||||
|
||||
@@ -267,7 +267,7 @@ func (c *Catbox) stop() {
|
||||
}
|
||||
|
||||
func (c *Catbox) linkServer(other *Catbox) error {
|
||||
conf := filepath.Join(c.ConfigDir, "catbox.conf")
|
||||
conf := filepath.Join(c.ConfigDir, "terrarium.conf")
|
||||
serversConf := filepath.Join(c.ConfigDir, "servers.conf")
|
||||
extra := fmt.Sprintf("servers-config = %s", serversConf)
|
||||
|
||||
|
@@ -11,20 +11,20 @@ import (
|
||||
|
||||
// Test one client sending a message to another client.
|
||||
func TestPRIVMSG(t *testing.T) {
|
||||
catbox, err := harnessCatbox("irc.example.org", "000")
|
||||
terrarium, err := harnessCatbox("irc.example.org", "000")
|
||||
if err != nil {
|
||||
t.Fatalf("error harnessing catbox: %s", err)
|
||||
t.Fatalf("error harnessing terrarium: %s", err)
|
||||
}
|
||||
defer catbox.stop()
|
||||
defer terrarium.stop()
|
||||
|
||||
client1 := NewClient("client1", "127.0.0.1", catbox.Port)
|
||||
client1 := NewClient("client1", "127.0.0.1", terrarium.Port)
|
||||
recvChan1, sendChan1, _, err := client1.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("error starting client: %s", err)
|
||||
}
|
||||
defer client1.Stop()
|
||||
|
||||
client2 := NewClient("client2", "127.0.0.1", catbox.Port)
|
||||
client2 := NewClient("client2", "127.0.0.1", terrarium.Port)
|
||||
recvChan2, _, _, err := client2.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("error starting client: %s", err)
|
||||
|
@@ -15,18 +15,18 @@ import (
|
||||
// Also test that the TS gets propagated between servers and a client on
|
||||
// another server gets the same TS
|
||||
func TestMODETS(t *testing.T) {
|
||||
catbox1, err := harnessCatbox("irc1.example.org", "001")
|
||||
require.NoError(t, err, "harness catbox")
|
||||
defer catbox1.stop()
|
||||
terrarium1, err := harnessCatbox("irc1.example.org", "001")
|
||||
require.NoError(t, err, "harness terrarium")
|
||||
defer terrarium1.stop()
|
||||
|
||||
catbox2, err := harnessCatbox("irc2.example.org", "002")
|
||||
require.NoError(t, err, "harness catbox")
|
||||
defer catbox2.stop()
|
||||
terrarium2, err := harnessCatbox("irc2.example.org", "002")
|
||||
require.NoError(t, err, "harness terrarium")
|
||||
defer terrarium2.stop()
|
||||
|
||||
err = catbox1.linkServer(catbox2)
|
||||
require.NoError(t, err, "link catbox1 to catbox2")
|
||||
err = catbox2.linkServer(catbox1)
|
||||
require.NoError(t, err, "link catbox2 to catbox1")
|
||||
err = terrarium1.linkServer(terrarium2)
|
||||
require.NoError(t, err, "link terrarium1 to terrarium2")
|
||||
err = terrarium2.linkServer(terrarium1)
|
||||
require.NoError(t, err, "link terrarium2 to terrarium1")
|
||||
|
||||
// Wait until we link.
|
||||
//
|
||||
@@ -37,18 +37,18 @@ func TestMODETS(t *testing.T) {
|
||||
linkRE := regexp.MustCompile(`Established link to irc2\.`)
|
||||
var attempts int
|
||||
for {
|
||||
if waitForLog(catbox1.LogChan, linkRE) {
|
||||
if waitForLog(terrarium1.LogChan, linkRE) {
|
||||
break
|
||||
}
|
||||
attempts++
|
||||
if attempts >= 5 {
|
||||
require.Fail(t, "failed to link")
|
||||
}
|
||||
require.NoError(t, err, catbox1.rehash(), "rehash catbox1")
|
||||
require.NoError(t, err, catbox2.rehash(), "rehash catbox2")
|
||||
require.NoError(t, err, terrarium1.rehash(), "rehash terrarium1")
|
||||
require.NoError(t, err, terrarium2.rehash(), "rehash terrarium2")
|
||||
}
|
||||
|
||||
client1 := NewClient("client1", "127.0.0.1", catbox1.Port)
|
||||
client1 := NewClient("client1", "127.0.0.1", terrarium1.Port)
|
||||
recvChan1, sendChan1, _, err := client1.Start()
|
||||
require.NoError(t, err, "start client")
|
||||
defer client1.Stop()
|
||||
@@ -110,7 +110,7 @@ func TestMODETS(t *testing.T) {
|
||||
t,
|
||||
creationTimeMessage,
|
||||
&irc.Message{
|
||||
Prefix: catbox1.Name,
|
||||
Prefix: terrarium1.Name,
|
||||
Command: "329",
|
||||
Params: []string{client1.GetNick(), "#test", creationTimeString},
|
||||
},
|
||||
@@ -124,7 +124,7 @@ func TestMODETS(t *testing.T) {
|
||||
|
||||
// Try a client on the other server and ensure they get the same time.
|
||||
|
||||
client2 := NewClient("client2", "127.0.0.1", catbox2.Port)
|
||||
client2 := NewClient("client2", "127.0.0.1", terrarium2.Port)
|
||||
recvChan2, sendChan2, _, err := client2.Start()
|
||||
require.NoError(t, err, "start client 2")
|
||||
defer client2.Stop()
|
||||
@@ -178,7 +178,7 @@ func TestMODETS(t *testing.T) {
|
||||
t,
|
||||
creationTimeMessage2,
|
||||
&irc.Message{
|
||||
Prefix: catbox2.Name,
|
||||
Prefix: terrarium2.Name,
|
||||
Command: "329",
|
||||
Params: []string{client2.GetNick(), "#test", creationTimeString},
|
||||
},
|
||||
|
10
util.go
10
util.go
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -439,6 +439,8 @@ func tlsVersionToString(version uint16) string {
|
||||
return "TLS 1.1"
|
||||
case tls.VersionTLS12:
|
||||
return "TLS 1.2"
|
||||
case tls.VersionTLS13:
|
||||
return "TLS 1.3"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown TLS version %x", version)
|
||||
}
|
||||
@@ -490,6 +492,12 @@ func cipherSuiteToString(suite uint16) string {
|
||||
return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
|
||||
case tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
|
||||
return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
return "TLS_AES_128_GCM_SHA256"
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
return "TLS_AES_256_GCM_SHA384"
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
return "TLS_CHACHA20_POLY1305_SHA256"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown cipher suite %x", suite)
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
package terrarium
|
||||
|
||||
// CreatedDate is the date we're built. This would be nice to generate
|
||||
// dynamically, but I don't want to complicate the build.
|
||||
const CreatedDate = "2019-01-01"
|
||||
const CreatedDate = "2019-07-08"
|
||||
|
||||
// Version is our version.
|
||||
const Version = "catbox-1.11.0"
|
||||
const Version = "terrarium-1.13.0"
|
||||
|
Reference in New Issue
Block a user