blob: 89983974ec98809271ed10f18f84915ff30b5d0c [file] [log] [blame]
// Copyright 2016 The Roughtime Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. */
// server is a very basic Roughtime server.
//
// First, run with the flag -generate-key. This will print out a private key
// and a JSON template for the server. Put the private key (as hex) in a file
// named "priv" and then run with no arguments.
package main
// TODO(agl): add a test once the client functionality has landed.
import (
"bytes"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"time"
"golang.org/x/crypto/ed25519"
"roughtime.googlesource.com/go/config"
"roughtime.googlesource.com/go/protocol"
)
var (
genKey = flag.Bool("generate-key", false, "Generate a new key pair")
privateKeyFile = flag.String("private-key", "priv", "Filename of the private key (hex encoded)")
port = flag.Int("port", 5333, "Port number to listen on")
)
func main() {
flag.Parse()
var err error
if *genKey {
err = generateKeyPair()
} else {
err = serveForever()
}
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}
func serveForever() error {
privateKeyHex, err := ioutil.ReadFile(*privateKeyFile)
if err != nil {
return errors.New("Cannot open private key: " + err.Error())
}
privateKey, err := hex.DecodeString(string(bytes.TrimSpace(privateKeyHex)))
if err != nil {
return errors.New("Cannot parse private key: " + err.Error())
}
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: *port})
if err != nil {
return errors.New("Cannot listen on port: " + err.Error())
}
onlinePublicKey, onlinePrivateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return errors.New("Cannot generate private key: " + err.Error())
}
// As this is just an example, the certificate is created covering the
// maximum possible range.
cert, err := protocol.CreateCertificate(0, ^uint64(0), onlinePublicKey, privateKey)
if err != nil {
return errors.New("Cannot generate certificate: " + err.Error())
}
log.Printf("Processing requests on port %d", *port)
var packetBuf [protocol.MinRequestSize]byte
for {
n, sourceAddr, err := conn.ReadFromUDP(packetBuf[:])
if err != nil {
log.Print(err)
}
if n < protocol.MinRequestSize {
continue
}
packet, err := protocol.Decode(packetBuf[:n])
if err != nil {
continue
}
nonce, ok := packet[protocol.TagNonce]
if !ok || len(nonce) != protocol.NonceSize {
continue
}
midpoint := uint64(time.Now().UnixNano() / 1000)
radius := uint32(1000000)
replies, err := protocol.CreateReplies([][]byte{nonce}, midpoint, radius, cert, onlinePrivateKey)
if err != nil {
log.Print(err)
continue
}
if len(replies) != 1 {
continue
}
conn.WriteToUDP(replies[0], sourceAddr)
}
}
func generateKeyPair() error {
rootPublic, rootPrivate, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return err
}
fmt.Printf("Private key: %x\n\n", rootPrivate)
exampleConfig := config.ServersJSON{
Servers: []config.Server{
config.Server{
Name: "FIXME",
PublicKeyType: "ed25519",
PublicKey: rootPublic,
Addresses: []config.ServerAddress{
config.ServerAddress{
Protocol: "udp",
Address: "FIXME",
},
},
},
},
}
jsonBytes, err := json.MarshalIndent(exampleConfig, "", " ")
if err != nil {
return err
}
os.Stdout.Write(jsonBytes)
os.Stdout.WriteString("\n")
return nil
}