Compare commits

...

14 commits

Author SHA1 Message Date
Augusto Dwenger J. b5c2560358 Replace deprecated ioutil.ReadFile with new func from os 2023-09-21 23:16:03 +02:00
Augusto Dwenger J. 61fc3ad141 Replace own ip extraction function with func from net package 2023-09-21 23:13:31 +02:00
Augusto Dwenger J. fd3e5530f9 Update crypto lib 2023-09-14 19:09:32 +02:00
Augusto Dwenger J. c12c77fb1d Update crypto lib 2022-09-24 17:05:36 +02:00
Augusto Dwenger J. fc116692a0 Increase project golang version to 1.19
Keep it up to date.
2022-08-11 18:16:32 +02:00
Augusto Dwenger J. 39a4ad47e1 Update crypto lib 2022-08-11 18:06:22 +02:00
Augusto Dwenger J. 7f421ecadb
Add a license section to the README 2022-05-21 16:15:44 +02:00
Augusto Dwenger J. ee5fd989b6
Update copyright holder information 2022-05-21 16:13:08 +02:00
Augusto Dwenger J. 1dc9ba16b5
Fix WaitGroup count on IPv4 only mode
It doesn't really matters, because we never mark them as done, but this
would make it easier if waiting for it would be required in the future.
2022-05-21 16:08:52 +02:00
Augusto Dwenger J. 8ebf7531e9
Move the ssh.ServerConfig creation to the main func
There is no need to create a config per request.
2022-05-21 16:08:32 +02:00
Augusto Dwenger J. f5a9473a9a
Extract previously inline PasswordCallback function into own function
I decided instead of defining the func inline in to a top level function
to reduce the nesting
2022-05-21 15:53:39 +02:00
Augusto Dwenger J. 52d38f1d36
Update go version in Dockerfile to 1.18 2022-05-21 15:51:57 +02:00
Augusto Dwenger J. 1a1119b9af
Increase project golang version 1.18
Keep it up to date.
2022-05-21 13:46:57 +02:00
Augusto Dwenger J. 9678d7ada2
Update crypto lib 2022-05-21 13:45:08 +02:00
7 changed files with 47 additions and 74 deletions

View file

@ -1,4 +1,4 @@
FROM docker.io/golang:1.16.5 AS build
FROM docker.io/golang:1.19 AS build
WORKDIR /src
COPY go.* /src/

View file

@ -1,4 +1,4 @@
MIT License Copyright (c) 2021 Augusto Dwenger J.
MIT License Copyright (c) 2021-2022 Augusto Dwenger J.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -54,3 +54,5 @@ FLAGS:
## Utils
Inside the `util` directory you might find some additional information like how to create Systemd service for sshlog.
## License
This project is being licensed under the [MIT license](LICENSE).

6
go.mod
View file

@ -1,8 +1,10 @@
module git.sr.ht/~hamburghammer/sshlog
go 1.16
go 1.19
require (
github.com/spf13/pflag v1.0.5
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/crypto v0.13.0
)
require golang.org/x/sys v0.12.0 // indirect

16
go.sum
View file

@ -1,13 +1,7 @@
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=

70
main.go
View file

@ -6,11 +6,9 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"strings"
"sync"
"time"
@ -49,6 +47,9 @@ func main() {
log.Fatal("Failed to parse private key")
}
serverConfig := ssh.ServerConfig{PasswordCallback: printConnectionData}
serverConfig.AddHostKey(hostKey)
log.Printf("Starting ssh logger on port %s...\n", port)
ipv4Listener, err := net.Listen("tcp", "0.0.0.0:"+port)
if err != nil {
@ -57,8 +58,8 @@ func main() {
defer ipv4Listener.Close()
wg := new(sync.WaitGroup)
wg.Add(2)
go startAccepting(ipv4Listener, hostKey)
wg.Add(1)
go startAccepting(ipv4Listener, serverConfig)
if !onlyIPv4 {
ipv6Listener, err := net.Listen("tcp", "[::1]:"+port)
@ -67,25 +68,26 @@ func main() {
}
defer ipv6Listener.Close()
go startAccepting(ipv6Listener, hostKey)
wg.Add(1)
go startAccepting(ipv6Listener, serverConfig)
}
wg.Wait() // Waits until it gets terminated
}
func startAccepting(listener net.Listener, hostKey ssh.Signer) {
func startAccepting(listener net.Listener, serverConfig ssh.ServerConfig) {
for {
con, err := listener.Accept()
if err != nil {
log.Println(err)
}
go printData(con, hostKey)
go connectionHandler(con, serverConfig)
}
}
func getKey(path string) []byte {
if path != "" {
privateBytes, err := ioutil.ReadFile(path)
privateBytes, err := os.ReadFile(path)
if err != nil {
log.Fatalf("Failed to load private key: %s", path)
}
@ -107,33 +109,36 @@ func getKey(path string) []byte {
return privateKeyPem
}
func printData(con net.Conn, hostKey ssh.Signer) {
serverConfig := ssh.ServerConfig{PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
ip := getIPWithoutPort(conn.RemoteAddr().String())
if isJson {
fmt.Printf(
"{\"date\": \"%s\", \"src\": \"%s\", \"username\": \"%s\", \"password\": \"%s\"}\n",
time.Now().Format(time.RFC3339),
ip,
conn.User(),
string(password),
)
} else {
log.Printf("SRC=%s USERNAME=%s PASSWORD=%s\n", ip, conn.User(), string(password))
}
return nil, fmt.Errorf("password rejected for %s", conn.User())
}}
serverConfig.AddHostKey(hostKey)
func connectionHandler(con net.Conn, serverConfig ssh.ServerConfig) {
_, _, _, err := ssh.NewServerConn(con, &serverConfig)
if err != nil {
return
}
}
func printConnectionData(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
responseErr := fmt.Errorf("password rejected for %s", conn.User())
ip, _, err := net.SplitHostPort(conn.RemoteAddr().String())
if err != nil {
fmt.Println(err)
return nil, responseErr
}
if isJson {
fmt.Printf(
"{\"date\": \"%s\", \"src\": \"%s\", \"username\": \"%s\", \"password\": \"%s\"}\n",
time.Now().Format(time.RFC3339),
ip,
conn.User(),
string(password),
)
} else {
log.Printf("SRC=%s USERNAME=%s PASSWORD=%s\n", ip, conn.User(), string(password))
}
return nil, responseErr
}
func printHelp() {
fmt.Println(`A small tool to log IPs, usernames and passwords from incoming ssh-auth requests.
@ -143,10 +148,3 @@ USAGE:
FLAGS:`)
flags.PrintDefaults()
}
func getIPWithoutPort(address string) string {
if strings.Contains(address, "]") { // Is IPv6
return strings.ReplaceAll(strings.Split(address, "]")[0], "[", "")
}
return strings.Split(address, ":")[0]
}

View file

@ -1,23 +0,0 @@
package main
import "testing"
func TestGetIPWithoutPort(t *testing.T) {
t.Run("IPv6", func(t *testing.T) {
got := getIPWithoutPort("[::1]:2222")
want := "::1"
if want != got {
t.Fatalf("Want '%s' but got '%s'", want, got)
}
})
t.Run("IPv4", func(t *testing.T) {
got := getIPWithoutPort("127.0.0.1:2222")
want := "127.0.0.1"
if want != got {
t.Fatalf("Want '%s' but got '%s'", want, got)
}
})
}