Add missing ident.go
Forgot to check in this file.
Fixes: 65302d3c1e
("Add an ident server")
This commit is contained in:
parent
745b3f67a0
commit
ba37d374ec
150
ident.go
Normal file
150
ident.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package soju
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var identdTimeout = 10 * time.Second
|
||||||
|
|
||||||
|
type identKey struct {
|
||||||
|
remoteHost string
|
||||||
|
remotePort int
|
||||||
|
localPort int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIdentKey(remoteAddr, localAddr string) (*identKey, error) {
|
||||||
|
remoteHost, remotePort, err := splitHostPort(remoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, localPort, err := splitHostPort(localAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &identKey{
|
||||||
|
remoteHost: remoteHost,
|
||||||
|
remotePort: remotePort,
|
||||||
|
localPort: localPort,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitHostPort(addr string) (host string, port int, err error) {
|
||||||
|
host, portStr, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
port, err = strconv.Atoi(portStr)
|
||||||
|
return host, port, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identd implements an ident server, as described in RFC 1413.
|
||||||
|
type Identd struct {
|
||||||
|
entries map[identKey]string
|
||||||
|
lock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIdentd() *Identd {
|
||||||
|
return &Identd{entries: make(map[identKey]string)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Identd) Store(remoteAddr, localAddr, ident string) {
|
||||||
|
k, err := newIdentKey(remoteAddr, localAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(remoteAddr, localAddr, ident)
|
||||||
|
s.lock.Lock()
|
||||||
|
s.entries[*k] = ident
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Identd) Delete(remoteAddr, localAddr string) {
|
||||||
|
k, err := newIdentKey(remoteAddr, localAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.lock.Lock()
|
||||||
|
delete(s.entries, *k)
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Identd) Serve(ln net.Listener) error {
|
||||||
|
for {
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to accept connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go s.handle(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Identd) handle(c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
remoteHost, _, err := net.SplitHostPort(c.RemoteAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(c)
|
||||||
|
|
||||||
|
// We only read to read lines with two port numbers
|
||||||
|
var buf [512]byte
|
||||||
|
scanner.Buffer(buf[:], len(buf))
|
||||||
|
|
||||||
|
for {
|
||||||
|
c.SetDeadline(time.Now().Add(identdTimeout))
|
||||||
|
if !scanner.Scan() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l := scanner.Text()
|
||||||
|
|
||||||
|
localPort, remotePort, err := parseIdentQuery(l)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(c, "%s : ERROR : INVALID-PORT\r\n", l)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
k := identKey{
|
||||||
|
remoteHost: remoteHost,
|
||||||
|
remotePort: remotePort,
|
||||||
|
localPort: localPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.lock.RLock()
|
||||||
|
ident := s.entries[k]
|
||||||
|
s.lock.RUnlock()
|
||||||
|
|
||||||
|
if ident == "" {
|
||||||
|
fmt.Fprintf(c, "%s : ERROR : NO-USER\r\n", l)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(c, "%s : USERID : OTHER : %s\r\n", l, ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseIdentQuery(l string) (localPort, remotePort int, err error) {
|
||||||
|
parts := strings.SplitN(l, ",", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return 0, 0, fmt.Errorf("expected two ports")
|
||||||
|
}
|
||||||
|
localStr, remoteStr := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
|
||||||
|
if localPort, err = strconv.Atoi(localStr); err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
if remotePort, err = strconv.Atoi(remoteStr); err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
if localPort <= 0 || remotePort <= 0 {
|
||||||
|
return 0, 0, fmt.Errorf("invalid port")
|
||||||
|
}
|
||||||
|
return localPort, remotePort, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user