More protocols

This commit is contained in:
2026-02-17 23:30:49 +01:00
parent 62a90a468d
commit 74a517a22a
15 changed files with 2268 additions and 21 deletions

View File

@@ -0,0 +1,188 @@
package aprsis
import (
"bufio"
"bytes"
"fmt"
"net"
"strings"
"sync"
"git.maze.io/go/ham/protocol"
"github.com/sirupsen/logrus"
)
const (
DefaultListenAddr = ":14580"
DefaultServerAddr = "rotate.aprs2.net:14580"
)
type Proxy struct {
Logger *logrus.Logger
Filter string
server string
listen net.Listener
packets chan *protocol.Packet
}
func NewProxy(listen, server string) (*Proxy, error) {
if _, err := net.ResolveTCPAddr("tcp", server); err != nil {
return nil, fmt.Errorf("aprsis: error resolving %q: %v", server, err)
}
listenAddr, err := net.ResolveTCPAddr("tcp", listen)
if err != nil {
return nil, fmt.Errorf("aprsis: error listening on %s: %v", listen, err)
}
listener, err := net.ListenTCP("tcp", listenAddr)
if err != nil {
return nil, fmt.Errorf("aprsis: error listening on %s: %v", listen, err)
}
proxy := &Proxy{
Logger: logrus.New(),
server: server,
listen: listener,
}
go proxy.accept()
return proxy, nil
}
func (proxy *Proxy) Close() error {
if proxy.packets != nil {
close(proxy.packets)
proxy.packets = nil
}
return proxy.listen.Close()
}
func (proxy *Proxy) RawPackets() <-chan *protocol.Packet {
if proxy.packets == nil {
proxy.packets = make(chan *protocol.Packet, 16)
}
return proxy.packets
}
func (proxy *Proxy) accept() {
for {
client, err := proxy.listen.Accept()
if err != nil {
proxy.Logger.Errorf("aprs-is proxy: error accepting client: %v", err)
continue
}
go proxy.handle(client)
}
}
func (proxy *Proxy) handle(client net.Conn) {
defer func() { _ = client.Close() }()
host, _, _ := net.SplitHostPort(client.RemoteAddr().String())
proxy.Logger.Infof("aprs-is proxy[%s]: new connection", host)
server, err := net.Dial("tcp", proxy.server)
if err != nil {
proxy.Logger.Warnf("aprs-is proxy[%s]: can't connecto to APRS-IS server %s: %v", host, proxy.server, err)
return
}
defer func() { _ = server.Close() }()
var (
wait sync.WaitGroup
call string
)
wait.Go(func() { proxy.proxy(client, server, host, "->", &call) })
wait.Go(func() { proxy.proxy(server, client, host, "<-", nil) })
wait.Wait()
}
func (proxy *Proxy) proxy(dst, src net.Conn, host, dir string, call *string) {
defer func() {
if tcp, ok := dst.(*net.TCPConn); ok {
_ = tcp.CloseWrite()
} else {
_ = dst.Close()
}
}()
reader := bufio.NewReader(src)
for {
line, err := reader.ReadBytes('\n')
if err != nil {
proxy.Logger.Warnf("aprs-is proxy[%s]: %s read error: %v", host, src.RemoteAddr(), err)
return
}
// proxy to remote unaltered
if len(line) > 0 {
if _, err = dst.Write(line); err != nil {
proxy.Logger.Warnf("aprs-is proxy[%s]: %s write error: %v", host, dst.RemoteAddr(), err)
return
}
}
// parse line
line = bytes.TrimRight(line, "\r\n")
if len(line) > 0 {
proxy.Logger.Tracef("aprs-is proxy[%s]: %s %s", host, dir, string(line))
if call != nil && strings.HasPrefix(string(line), "# logresp ") {
// server responds to client login
part := strings.SplitN(string(line), " ", 5)
if len(part) > 4 && part[3] == "verified," {
*call = part[2]
proxy.Logger.Infof("aprs-is proxy[%s]: logged in as %s", host, *call)
if proxy.Filter != "" {
proxy.Logger.Tracef("aprs-is proxy[%s]: %s filter %s", host, dir, proxy.Filter)
if _, err = fmt.Fprintf(src, "filter %s\r\n", proxy.Filter); err != nil {
proxy.Logger.Warnf("aprs-is proxy[%s]: %s write error: %v", host, src.RemoteAddr(), err)
return
}
}
}
}
if !isCommand(line) {
proxy.handleRawPacket(line)
}
}
}
}
func (proxy *Proxy) handleRawPacket(data []byte) {
if proxy.packets == nil {
return
}
select {
case proxy.packets <- &protocol.Packet{
Protocol: "aprs",
Raw: data,
}:
default:
proxy.Logger.Warn("aprs-is proxy: raw packet channel full, dropping packet")
}
}
func isCommand(line []byte) bool {
if len(line) == 0 {
return true
}
if line[0] == '#' {
return true
}
if i := bytes.IndexByte(line, ' '); i > -1 {
switch strings.ToLower(string(line[:i])) {
case "user", "filter":
return true
}
}
return false
}