Add localports=,remoteports= parsing

master
Merlijn Wajer 7 years ago
parent f902444b64
commit c1a9590f84
  1. 115
      sshd.go

@ -21,7 +21,7 @@ import (
// TODO: Use defer where useful
var (
authorisedKeys map[string]string
authorisedKeys map[string]deviceInfo
listenport = flag.Int("listenport", 2200, "Port to listen on for incoming ssh connections")
hostkey = flag.String("hostkey", "id_rsa", "Server host key to load")
@ -43,6 +43,12 @@ type bindInfo struct {
Addr string
}
type deviceInfo struct {
LocalPorts string
RemotePorts string
Comment string
}
/* RFC4254 7.2 */
type directTCPPayload struct {
Addr string // To connect to
@ -77,9 +83,11 @@ func main() {
config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
if ports, found := authorisedKeys[string(key.Marshal())]; found {
if deviceinfo, found := authorisedKeys[string(key.Marshal())]; found {
return &ssh.Permissions{
CriticalOptions: map[string]string{"ports": ports},
CriticalOptions: map[string]string{"name": deviceinfo.Comment,
"localports": deviceinfo.LocalPorts,
"remoteports": deviceinfo.RemotePorts},
}, nil
}
@ -111,7 +119,18 @@ func main() {
return
}
client := sshClient{"TODO FIXME XXX", sshConn, make(map[string]net.Listener), nil, nil}
client := sshClient{sshConn.Permissions.CriticalOptions["name"], sshConn, make(map[string]net.Listener), nil, nil}
allowedLocalPorts := sshConn.Permissions.CriticalOptions["localports"]
allowedRemotePorts := sshConn.Permissions.CriticalOptions["remoteports"]
if *verbose {
log.Printf("Connection from %s (%s). Allowed local ports: %s remote ports: %s", sshConn.RemoteAddr(), sshConn.ClientVersion(), allowedLocalPorts, allowedRemotePorts)
}
// Parsing a second time should not error, so we can ignore the error
// safely
client.AllowedLocalPorts, _ = parsePorts(allowedLocalPorts)
client.AllowedRemotePorts, _ = parsePorts(allowedRemotePorts)
go func() {
err := client.Conn.Wait()
@ -128,19 +147,6 @@ func main() {
}
}()
allowedPorts := sshConn.Permissions.CriticalOptions["ports"]
if *verbose {
log.Printf("Connection from %s (%s). Allowed ports: %s", sshConn.RemoteAddr(), sshConn.ClientVersion(), allowedPorts)
}
// Parsing a second time should not error, so we can ignore the error
// safely
ports, _ := parsePorts(allowedPorts)
// TODO: Don't share same port/host limit
client.AllowedLocalPorts = ports
client.AllowedRemotePorts = ports
go handleRequest(&client, reqs)
// Accept all channels
@ -355,18 +361,6 @@ func serve(cssh ssh.Channel, conn net.Conn) {
}()
}
func parsePorts(portstr string) (p []uint32, err error) {
ports := strings.Split(portstr, ":")
for _, port := range ports {
port, err := strconv.ParseUint(port, 10, 32)
if err != nil {
return p, err
}
p = append(p, uint32(port))
}
return
}
func loadHostKeys(config *ssh.ServerConfig) {
privateBytes, err := ioutil.ReadFile(*hostkey)
if err != nil {
@ -382,39 +376,41 @@ func loadHostKeys(config *ssh.ServerConfig) {
}
func loadAuthorisedKeys(authorisedkeys string) {
authorisedKeys = map[string]string{}
authorisedKeys = map[string]deviceInfo{}
authorisedKeysBytes, err := ioutil.ReadFile(authorisedkeys)
if err != nil {
log.Fatal("Cannot load authorised keys")
}
for len(authorisedKeysBytes) > 0 {
pubkey, _, options, rest, err := ssh.ParseAuthorizedKey(authorisedKeysBytes)
pubkey, comment, options, rest, err := ssh.ParseAuthorizedKey(authorisedKeysBytes)
if err != nil {
log.Fatal(err)
}
log.Println("Options:", options)
if len(options) != 1 {
log.Fatal(fmt.Errorf("Only one option is accepted: \"ports=...\""))
}
option := options[0]
if !strings.HasPrefix(option, "ports=") {
log.Fatal(fmt.Errorf("Options does not start with \"ports=\""))
devinfo := deviceInfo{
Comment: comment,
}
ports := option[len("ports="):]
_, err = parsePorts(ports)
if err != nil {
log.Fatal(err)
for _, option := range options {
ports, err := parseOption(option, "local")
if err != nil {
ports, err := parseOption(option, "remote")
if err != nil {
log.Fatal(err)
} else {
devinfo.RemotePorts = ports
}
} else {
devinfo.LocalPorts = ports
}
}
authorisedKeys[string(pubkey.Marshal())] = ports
authorisedKeys[string(pubkey.Marshal())] = devinfo
authorisedKeysBytes = rest
}
}
@ -456,3 +452,32 @@ func portPermitted(port uint32, ports []uint32) bool {
return ok
}
func parseOption(option string, prefix string) (string, error) {
str := fmt.Sprintf("%sports=", prefix)
if !strings.HasPrefix(option, str) {
return "", fmt.Errorf("Option does not start with %s", str)
}
ports := option[len(str):]
_, err := parsePorts(ports)
if err != nil {
log.Fatal(err)
}
return ports, nil
}
func parsePorts(portstr string) (p []uint32, err error) {
ports := strings.Split(portstr, ":")
for _, port := range ports {
port, err := strconv.ParseUint(port, 10, 32)
if err != nil {
return p, err
}
p = append(p, uint32(port))
}
return
}

Loading…
Cancel
Save