Skip to content

Instantly share code, notes, and snippets.

@upperwal
Last active December 22, 2018 18:03
Show Gist options
  • Save upperwal/ffecb9e8015a87a128eba9c7beefd6b9 to your computer and use it in GitHub Desktop.
Save upperwal/ffecb9e8015a87a128eba9c7beefd6b9 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"errors"
"flag"
"fmt"
"math/big"
mrand "math/rand"
"net"
"os"
"strings"
"time"
"github.com/gogo/protobuf/proto"
"github.com/libp2p/go-libp2p-crypto"
ic "github.com/libp2p/go-libp2p-crypto"
pb "github.com/libp2p/go-libp2p-crypto/pb"
quic "github.com/lucas-clemente/quic-go"
)
const hostname = "quic.ipfs"
const certValidityPeriod = 180 * 24 * time.Hour
func keyToCertificate(sk ic.PrivKey) (interface{}, *x509.Certificate, error) {
sn, err := rand.Int(rand.Reader, big.NewInt(1<<62))
if err != nil {
return nil, nil, err
}
tmpl := &x509.Certificate{
SerialNumber: sn,
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(certValidityPeriod),
IsCA: true,
BasicConstraintsValid: true,
}
var publicKey, privateKey interface{}
keyBytes, err := sk.Bytes()
if err != nil {
return nil, nil, err
}
pbmes := new(pb.PrivateKey)
if err := proto.Unmarshal(keyBytes, pbmes); err != nil {
return nil, nil, err
}
switch pbmes.GetType() {
case pb.KeyType_RSA:
k, err := x509.ParsePKCS1PrivateKey(pbmes.GetData())
if err != nil {
return nil, nil, err
}
publicKey = &k.PublicKey
privateKey = k
// TODO: add support for ECDSA
default:
return nil, nil, errors.New("unsupported key type for TLS")
}
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, publicKey, privateKey)
if err != nil {
return nil, nil, err
}
cert, err := x509.ParseCertificate(certDER)
if err != nil {
return nil, nil, err
}
return privateKey, cert, nil
}
func generateConfig(privKey ic.PrivKey) (*tls.Config, error) {
key, hostCert, err := keyToCertificate(privKey)
if err != nil {
return nil, err
}
// The ephemeral key used just for a couple of connections (or a limited time).
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
// Sign the ephemeral key using the host key.
// This is the only time that the host's private key of the peer is needed.
// Note that this step could be done asynchronously, such that a running node doesn't need access its private key at all.
certTemplate := &x509.Certificate{
DNSNames: []string{hostname},
SerialNumber: big.NewInt(1),
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(certValidityPeriod),
}
certDER, err := x509.CreateCertificate(rand.Reader, certTemplate, hostCert, ephemeralKey.Public(), key)
if err != nil {
return nil, err
}
cert, err := x509.ParseCertificate(certDER)
if err != nil {
return nil, err
}
return &tls.Config{
ServerName: hostname,
InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves.
ClientAuth: tls.RequireAnyClientCert,
Certificates: []tls.Certificate{{
Certificate: [][]byte{cert.Raw, hostCert.Raw},
PrivateKey: ephemeralKey,
}},
}, nil
}
var quicConfig = &quic.Config{
Versions: []quic.VersionNumber{101},
MaxIncomingStreams: 1000,
MaxIncomingUniStreams: -1, // disable unidirectional streams
MaxReceiveStreamFlowControlWindow: 3 * (1 << 20), // 3 MB
MaxReceiveConnectionFlowControlWindow: 4.5 * (1 << 20), // 4.5 MB
AcceptCookie: func(clientAddr net.Addr, cookie *quic.Cookie) bool {
// TODO(#6): require source address validation when under load
return true
},
KeepAlive: true,
}
func handleAccept(l quic.Listener) {
for {
s, err := l.Accept()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Connected to: ", s.RemoteAddr())
/* if !_remote {
ss, err := quic.Dial(*_pconn, s.RemoteAddr(), "0.0.0.0:0", _tlsConfig, quicConfig)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Back Connected to: ", ss.RemoteAddr())
} */
}
}
func main() {
port := flag.String("p", "0", "port")
flag.Parse()
pconn, err := net.ListenPacket("udp4", "0.0.0.0:"+*port)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("My: ", pconn.LocalAddr())
pconn_laddr := pconn.LocalAddr().String()
idx := strings.LastIndex(pconn_laddr, ":")
port_str := pconn_laddr[idx+1:]
r := mrand.New(mrand.NewSource(int64(35544)))
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
if err != nil {
panic(err)
}
tlsConf, err := generateConfig(prvKey)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
l, err := quic.Listen(pconn, tlsConf, quicConfig)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
go handleAccept(l)
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
text = strings.TrimRight(text, "\n")
fmt.Println("Remote: ", text)
addr, err := net.ResolveUDPAddr("udp", text)
if err != nil {
fmt.Println("ResolveUDPAddr err ", err)
os.Exit(1)
}
s, err := quic.Dial(pconn, addr, "192.168.0.102:"+port_str, tlsConf, quicConfig)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Connected to: ", s.RemoteAddr(), s.LocalAddr())
}
select {}
}
package main
import (
"bufio"
"flag"
"fmt"
"net"
"os"
"strings"
)
func handleIncoming(conn *net.UDPConn) {
b := make([]byte, 1024*10)
for {
n, addr, err := conn.ReadFromUDP(b)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Read", n, "bytes from", addr, "data", string(b[:n]))
}
}
func main() {
port := flag.String("p", "0", "port")
flag.Parse()
laddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:"+*port)
pconn, err := net.ListenUDP("udp4", laddr)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("My: ", pconn.LocalAddr())
go handleIncoming(pconn)
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
text = strings.TrimRight(text, "\n")
fmt.Println("Remote: ", text)
raddr, err := net.ResolveUDPAddr("udp", text)
n, err := pconn.WriteTo([]byte("Abhishek"), raddr)
if err != nil {
fmt.Println(err)
}
fmt.Println("Written: ", n)
}
select {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment