Compare commits
11 Commits
vendor#19
...
secure_cli
Author | SHA1 | Date | |
---|---|---|---|
![]() |
092f638984 | ||
![]() |
9e075dde67 | ||
![]() |
20be29bcef | ||
![]() |
34c3be0a88 | ||
![]() |
be246a3bc4 | ||
![]() |
4fb452b2c0 | ||
![]() |
d707382a78 | ||
![]() |
7620a3c282 | ||
![]() |
18a3e2f2c3 | ||
![]() |
d046a9863f | ||
![]() |
a1450a81d6 |
@@ -46,4 +46,4 @@ $ git push -u origin my-feature
|
||||
|
||||
When describing your bug report; please be concise and as detailed as you can
|
||||
so we can easily work out what the problem is. It's also very helpful if you
|
||||
are able to provide a test case that repeatedly demonstrates the bug at hand:
|
||||
are able to provide a test case that repeatedly demonstrates the bug at hand.
|
||||
|
2
Makefile
2
Makefile
@@ -6,7 +6,7 @@ APP=eris
|
||||
PACKAGE=irc
|
||||
REPO?=prologic/$(APP)
|
||||
TAG?=latest
|
||||
BUILD?=-dev
|
||||
BUILD?=dev
|
||||
|
||||
all: dev
|
||||
|
||||
|
46
README.md
46
README.md
@@ -55,6 +55,40 @@ Or (*not recommended*)P
|
||||
* Secure connection tracking (+z) and SecureOnly user mode (+Z)
|
||||
* Secure channels (+Z)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```#!bash
|
||||
$ go get github.com/prologic/eris
|
||||
$ cat > ircd.yml <<EOF
|
||||
network:
|
||||
name: Test
|
||||
server:
|
||||
name: Test
|
||||
listen:
|
||||
- ":6667"
|
||||
EOF
|
||||
$ eris
|
||||
```
|
||||
|
||||
If you want TLS (**recommended**) then:
|
||||
|
||||
```#!bash
|
||||
$ go get github.com/prologic/mksslcert
|
||||
$ mksslcert
|
||||
```
|
||||
|
||||
This generates a self-signed cert `cert.pem` and `key.pem` into the `$PWD`.
|
||||
|
||||
Then add a `tlslisten` block to your config:
|
||||
|
||||
```#!yaml
|
||||
server:
|
||||
tlslisten:
|
||||
":6697":
|
||||
key: key.pem
|
||||
cert: cert.pem
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```#!bash
|
||||
@@ -73,6 +107,14 @@ $ go install github.com/prologic/mkpasswd
|
||||
$ mkpasswd
|
||||
```
|
||||
|
||||
Self-signed certificates can also be generated using the `mksslcert` tool
|
||||
from [prologic/mksslcert](https://github.com/prologic/mksslcert):
|
||||
|
||||
```#!bash
|
||||
$ go install github.com/prologic/mksslcert
|
||||
$ mksslcert
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
To run simply run the `eris` binary (*assuming a `ircd.yml` in the current directory*):
|
||||
@@ -93,9 +135,9 @@ You may want to customize the configuration however and create your own image ba
|
||||
$ docker stack deploy -c docker-compose.yml eris
|
||||
```
|
||||
|
||||
Which assumes a `ircd.yml` coniguration fiel int he current directory which Docker will use to distribute as the configuration. The `docker-compose.yml` (*Docker Stackfile*) is available at the root of this repository.
|
||||
Which assumes a `ircd.yml` coniguration file in the current directory which Docker will use to distribute as the configuration. The `docker-compose.yml` (*Docker Stackfile*) is available at the root of this repository.
|
||||
|
||||
## Related Proejcts
|
||||
## Related Projects
|
||||
|
||||
There are a number of supported accompanying services that are being developed alongside Eris:
|
||||
|
||||
|
@@ -155,16 +155,16 @@ func (channel *Channel) Join(client *Client, key Text) {
|
||||
return
|
||||
}
|
||||
|
||||
isInvited := channel.lists[InviteMask].Match(client.UserHost())
|
||||
isInvited := channel.lists[InviteMask].Match(client.UserHost(false))
|
||||
if !isOperator && channel.flags.Has(InviteOnly) && !isInvited {
|
||||
client.ErrInviteOnlyChan(channel)
|
||||
return
|
||||
}
|
||||
|
||||
if channel.lists[BanMask].Match(client.UserHost()) &&
|
||||
if channel.lists[BanMask].Match(client.UserHost(false)) &&
|
||||
!isInvited &&
|
||||
!isOperator &&
|
||||
!channel.lists[ExceptMask].Match(client.UserHost()) {
|
||||
!channel.lists[ExceptMask].Match(client.UserHost(false)) {
|
||||
client.ErrBannedFromChan(channel)
|
||||
return
|
||||
}
|
||||
@@ -508,7 +508,7 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
||||
}
|
||||
|
||||
if channel.flags.Has(InviteOnly) {
|
||||
channel.lists[InviteMask].Add(invitee.UserHost())
|
||||
channel.lists[InviteMask].Add(invitee.UserHost(false))
|
||||
}
|
||||
|
||||
inviter.RplInviting(invitee, channel.name)
|
||||
|
@@ -26,6 +26,7 @@ type Client struct {
|
||||
hasQuit bool
|
||||
hops uint
|
||||
hostname Name
|
||||
hostmask Name // Cloacked hostname (SHA256)
|
||||
pingTime time.Time
|
||||
idleTimer *time.Timer
|
||||
nick Name
|
||||
@@ -83,6 +84,7 @@ func (client *Client) readloop() {
|
||||
|
||||
// Set the hostname for this client.
|
||||
client.hostname = AddrLookupHostname(client.socket.conn.RemoteAddr())
|
||||
client.hostmask = NewName(SHA256(client.hostname.String()))
|
||||
|
||||
for err == nil {
|
||||
if line, err = client.socket.Read(); err != nil {
|
||||
@@ -220,6 +222,12 @@ func (client *Client) destroy() {
|
||||
|
||||
// clean up server
|
||||
|
||||
if _, ok := client.socket.conn.(*tls.Conn); ok {
|
||||
client.server.metrics.GaugeVec("server", "clients").WithLabelValues("secure").Dec()
|
||||
} else {
|
||||
client.server.metrics.GaugeVec("server", "clients").WithLabelValues("insecure").Dec()
|
||||
}
|
||||
|
||||
client.server.connections.Dec()
|
||||
client.server.clients.Remove(client)
|
||||
|
||||
@@ -233,6 +241,7 @@ func (client *Client) destroy() {
|
||||
}
|
||||
|
||||
close(client.replies)
|
||||
client.replies = nil
|
||||
|
||||
client.socket.Close()
|
||||
|
||||
@@ -279,11 +288,14 @@ func (c *Client) ModeString() (str string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) UserHost() Name {
|
||||
func (c *Client) UserHost(cloacked bool) Name {
|
||||
username := "*"
|
||||
if c.HasUsername() {
|
||||
username = c.username.String()
|
||||
}
|
||||
if cloacked {
|
||||
return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostmask))
|
||||
}
|
||||
return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname))
|
||||
}
|
||||
|
||||
@@ -303,7 +315,7 @@ func (c *Client) Nick() Name {
|
||||
}
|
||||
|
||||
func (c *Client) Id() Name {
|
||||
return c.UserHost()
|
||||
return c.UserHost(true)
|
||||
}
|
||||
|
||||
func (c *Client) String() string {
|
||||
@@ -346,7 +358,9 @@ func (client *Client) ChangeNickname(nickname Name) {
|
||||
}
|
||||
|
||||
func (client *Client) Reply(reply string) {
|
||||
client.replies <- reply
|
||||
if client.replies != nil {
|
||||
client.replies <- reply
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) Quit(message Text) {
|
||||
|
@@ -105,7 +105,7 @@ func (clients *ClientLookupSet) FindAll(userhost Name) *ClientSet {
|
||||
|
||||
var casemappedNickMask string
|
||||
for _, client := range clients.nicks {
|
||||
casemappedNickMask = client.UserHost().String()
|
||||
casemappedNickMask = client.UserHost(false).String()
|
||||
if matcher.Match(casemappedNickMask) {
|
||||
set.Add(client)
|
||||
}
|
||||
@@ -123,7 +123,7 @@ func (clients *ClientLookupSet) Find(userhost Name) *Client {
|
||||
|
||||
var casemappedNickMask string
|
||||
for _, client := range clients.nicks {
|
||||
casemappedNickMask = client.UserHost().String()
|
||||
casemappedNickMask = client.UserHost(false).String()
|
||||
if matcher.Match(casemappedNickMask) {
|
||||
return client
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ var DefObjectives = map[float64]float64{
|
||||
type Metrics struct {
|
||||
namespace string
|
||||
metrics map[string]prometheus.Metric
|
||||
gaugevecs map[string]*prometheus.GaugeVec
|
||||
sumvecs map[string]*prometheus.SummaryVec
|
||||
}
|
||||
|
||||
@@ -27,6 +28,7 @@ func NewMetrics(namespace string) *Metrics {
|
||||
return &Metrics{
|
||||
namespace: namespace,
|
||||
metrics: make(map[string]prometheus.Metric),
|
||||
gaugevecs: make(map[string]*prometheus.GaugeVec),
|
||||
sumvecs: make(map[string]*prometheus.SummaryVec),
|
||||
}
|
||||
}
|
||||
@@ -101,6 +103,24 @@ func (m *Metrics) NewGaugeFunc(subsystem, name, help string, f func() float64) p
|
||||
return guage
|
||||
}
|
||||
|
||||
func (m *Metrics) NewGaugeVec(subsystem, name, help string, labels []string) *prometheus.GaugeVec {
|
||||
gauagevec := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: m.namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: name,
|
||||
Help: help,
|
||||
},
|
||||
labels,
|
||||
)
|
||||
|
||||
key := fmt.Sprintf("%s_%s", subsystem, name)
|
||||
m.gaugevecs[key] = gauagevec
|
||||
prometheus.MustRegister(gauagevec)
|
||||
|
||||
return gauagevec
|
||||
}
|
||||
|
||||
func (m *Metrics) NewSummary(subsystem, name, help string) prometheus.Summary {
|
||||
summary := prometheus.NewSummary(
|
||||
prometheus.SummaryOpts{
|
||||
@@ -148,6 +168,11 @@ func (m *Metrics) Gauge(subsystem, name string) prometheus.Gauge {
|
||||
return m.metrics[key].(prometheus.Gauge)
|
||||
}
|
||||
|
||||
func (m *Metrics) GaugeVec(subsystem, name string) *prometheus.GaugeVec {
|
||||
key := fmt.Sprintf("%s_%s", subsystem, name)
|
||||
return m.gaugevecs[key]
|
||||
}
|
||||
|
||||
func (m *Metrics) Summary(subsystem, name string) prometheus.Summary {
|
||||
key := fmt.Sprintf("%s_%s", subsystem, name)
|
||||
return m.metrics[key].(prometheus.Summary)
|
||||
|
55
irc/reply.go
55
irc/reply.go
@@ -260,16 +260,16 @@ func (target *Client) RplWhois(client *Client) {
|
||||
}
|
||||
target.RplWhoisServer(client)
|
||||
target.RplWhoisLoggedIn(client)
|
||||
target.RplEndOfWhois()
|
||||
target.RplEndOfWhois(client)
|
||||
}
|
||||
|
||||
func (target *Client) RplWhoisUser(client *Client) {
|
||||
var clientHost Name
|
||||
|
||||
if client.flags[SecureConn] {
|
||||
if target.flags[Operator] {
|
||||
clientHost = client.hostname
|
||||
} else {
|
||||
clientHost = NewName("SECURED")
|
||||
clientHost = client.hostmask
|
||||
}
|
||||
|
||||
target.NumericReply(
|
||||
@@ -324,9 +324,12 @@ func (target *Client) RplWhoisServer(client *Client) {
|
||||
)
|
||||
}
|
||||
|
||||
func (target *Client) RplEndOfWhois() {
|
||||
target.NumericReply(RPL_ENDOFWHOIS,
|
||||
":End of WHOIS list")
|
||||
func (target *Client) RplEndOfWhois(client *Client) {
|
||||
target.NumericReply(
|
||||
RPL_ENDOFWHOIS,
|
||||
"%s :End of WHOIS list",
|
||||
client.Nick(),
|
||||
)
|
||||
}
|
||||
|
||||
func (target *Client) RplChannelModeIs(channel *Channel) {
|
||||
@@ -337,6 +340,14 @@ func (target *Client) RplChannelModeIs(channel *Channel) {
|
||||
// <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
|
||||
// :<hopcount> <real name>
|
||||
func (target *Client) RplWhoReply(channel *Channel, client *Client) {
|
||||
var clientHost Name
|
||||
|
||||
if target.flags[Operator] {
|
||||
clientHost = client.hostname
|
||||
} else {
|
||||
clientHost = client.hostmask
|
||||
}
|
||||
|
||||
channelName := "*"
|
||||
flags := ""
|
||||
|
||||
@@ -366,9 +377,18 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
|
||||
}
|
||||
}
|
||||
}
|
||||
target.NumericReply(RPL_WHOREPLY,
|
||||
"%s %s %s %s %s %s :%d %s", channelName, client.username, client.hostname,
|
||||
client.server.name, client.Nick(), flags, client.hops, client.realname)
|
||||
target.NumericReply(
|
||||
RPL_WHOREPLY,
|
||||
"%s %s %s %s %s %s :%d %s",
|
||||
channelName,
|
||||
client.username,
|
||||
clientHost,
|
||||
client.server.name,
|
||||
client.Nick(),
|
||||
flags,
|
||||
client.hops,
|
||||
client.realname,
|
||||
)
|
||||
}
|
||||
|
||||
// <name> :End of WHO list
|
||||
@@ -579,9 +599,22 @@ func (target *Client) RplLUserMe() {
|
||||
}
|
||||
|
||||
func (target *Client) RplWhoWasUser(whoWas *WhoWas) {
|
||||
target.NumericReply(RPL_WHOWASUSER,
|
||||
var whoWasHost Name
|
||||
|
||||
if target.flags[Operator] {
|
||||
whoWasHost = whoWas.hostname
|
||||
} else {
|
||||
whoWasHost = whoWas.hostmask
|
||||
}
|
||||
|
||||
target.NumericReply(
|
||||
RPL_WHOWASUSER,
|
||||
"%s %s %s * :%s",
|
||||
whoWas.nickname, whoWas.username, whoWas.hostname, whoWas.realname)
|
||||
whoWas.nickname,
|
||||
whoWas.username,
|
||||
whoWasHost,
|
||||
whoWas.realname,
|
||||
)
|
||||
}
|
||||
|
||||
func (target *Client) RplEndOfWhoWas(nickname Name) {
|
||||
|
@@ -123,15 +123,22 @@ func NewServer(config *Config) *Server {
|
||||
},
|
||||
)
|
||||
|
||||
// server clients gauge
|
||||
// server registered (clients) gauge
|
||||
server.metrics.NewGaugeFunc(
|
||||
"server", "clients",
|
||||
"server", "registered",
|
||||
"Number of registered clients connected",
|
||||
func() float64 {
|
||||
return float64(server.clients.Count())
|
||||
},
|
||||
)
|
||||
|
||||
// server clients gauge (by secure/insecire)
|
||||
server.metrics.NewGaugeVec(
|
||||
"server", "clients",
|
||||
"Number of registered clients connected (by secure/insecure)",
|
||||
[]string{"secure"},
|
||||
)
|
||||
|
||||
// server channels gauge
|
||||
server.metrics.NewGaugeFunc(
|
||||
"server", "channels",
|
||||
@@ -217,6 +224,12 @@ func (s *Server) acceptor(listener net.Listener) {
|
||||
}
|
||||
log.Debugf("%s accept: %s", s, conn.RemoteAddr())
|
||||
|
||||
if _, ok := conn.(*tls.Conn); ok {
|
||||
s.metrics.GaugeVec("server", "clients").WithLabelValues("secure").Inc()
|
||||
} else {
|
||||
s.metrics.GaugeVec("server", "clients").WithLabelValues("insecure").Inc()
|
||||
}
|
||||
|
||||
s.connections.Inc()
|
||||
s.newConns <- conn
|
||||
}
|
||||
|
11
irc/utils.go
Normal file
11
irc/utils.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func SHA256(data string) string {
|
||||
hash := sha256.Sum256([]byte(data))
|
||||
return fmt.Sprintf("%x", hash)
|
||||
}
|
@@ -1,14 +1,18 @@
|
||||
package irc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
//PackageName package name
|
||||
Package = "eris"
|
||||
|
||||
// Version release version
|
||||
Version = "1.6.0"
|
||||
Version = "1.6.2"
|
||||
|
||||
// Build will be overwritten automatically by the build system
|
||||
Build = "-dev"
|
||||
Build = "dev"
|
||||
|
||||
// GitCommit will be overwritten automatically by the build system
|
||||
GitCommit = "HEAD"
|
||||
@@ -16,5 +20,5 @@ var (
|
||||
|
||||
// FullVersion display the full version and build
|
||||
func FullVersion() string {
|
||||
return Package + " v" + Version + Build + " (" + GitCommit + ")"
|
||||
return fmt.Sprintf("%s-%s-%s@%s", Package, Version, Build, GitCommit)
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ type WhoWas struct {
|
||||
nickname Name
|
||||
username Name
|
||||
hostname Name
|
||||
hostmask Name
|
||||
realname Text
|
||||
}
|
||||
|
||||
@@ -33,6 +34,7 @@ func (list *WhoWasList) Append(client *Client) {
|
||||
nickname: client.Nick(),
|
||||
username: client.username,
|
||||
hostname: client.hostname,
|
||||
hostmask: client.hostmask,
|
||||
realname: client.realname,
|
||||
}
|
||||
list.end = (list.end + 1) % len(list.buffer)
|
||||
|
Reference in New Issue
Block a user