@ -14,6 +14,7 @@ import (
"log"
"net"
"net/url"
"os"
"os/user"
"strconv"
"strings"
@ -21,12 +22,6 @@ import (
"time"
)
import (
//#include <unistd.h>
//#include <errno.h>
"C"
)
type tlsConnectionInfo struct {
TlsVersion uint16 ` json:"tls_version" `
CipherSuite uint16 ` json:"cipher_suite" `
@ -129,21 +124,24 @@ _____________________
= > https : //tildegit.org/nervuri/client-hello-mirror Source (contributions welcome)
= > https : //www.gnu.org/licenses/agpl-3.0.en.html License: AGPL-3.0-or-later`
// Copy the Client Hello message before starting the TLS handshake.
func peek ( conn net . Conn , tlsConfig * tls . Config ) {
// Copy the Client Hello before starting the TLS handshake.
defer conn . Close ( )
var buf bytes . Buffer
_ , err := io . CopyN ( & buf , conn , 5 ) // TLS record header
// Copy TLS record header.
_ , err := io . CopyN ( & buf , conn , 5 )
if err != nil {
log . Println ( err )
return
}
// Check if this is a TLS handshake record.
if buf . Bytes ( ) [ 0 ] != 0x16 {
// Not a Client Hello message.
return
}
length := binary . BigEndian . Uint16 ( buf . Bytes ( ) [ 3 : 5 ] )
_ , err = io . CopyN ( & buf , conn , int64 ( length ) )
// Extract handshake message length.
handshakeMessageLength := binary . BigEndian . Uint16 ( buf . Bytes ( ) [ 3 : 5 ] )
// Copy handshake message (should be a Client Hello).
_ , err = io . CopyN ( & buf , conn , int64 ( handshakeMessageLength ) )
if err != nil {
log . Println ( err )
return
@ -277,11 +275,11 @@ func main() {
// Parse arguments
flag . StringVar ( & certFile , "c" , "" , "path to certificate file" )
flag . StringVar ( & keyFile , "k" , "" , "path to private key file" )
flag . StringVar ( & userToSwitchTo , "u" , " www-data ", "user to switch to, if running as root" )
flag . StringVar ( & userToSwitchTo , "u" , " ", "user to switch to, if running as root" )
flag . Parse ( )
hostAndPort = flag . Arg ( 0 )
if certFile == "" || keyFile == "" || hostAndPort == "" {
fmt . Println ( "usage: client-hello-mirror -c cert.pem -k key.pem host:port")
fmt . Println ( "usage: client-hello-mirror -c cert.pem -k key.pem [-u user] host:port")
return
}
@ -307,36 +305,48 @@ func main() {
defer ln . Close ( )
// Drop root
if syscall . Getuid ( ) == 0 {
if syscall . Getuid ( ) == 0 { // running as root
if userToSwitchTo == "" {
fmt . Println ( " Running as root. Please specify an unprivileged user to switch to, using the -u flag ")
return
fmt . Println ( " When running as root, use the -u option to switch to an unprivileged user. ")
os . Exit ( 1 )
}
// Get user and group IDs for the user we want to switch to.
userInfo , err := user . Lookup ( userToSwitchTo )
if err != nil {
fmt . Println ( err )
if userToSwitchTo == "www-data" {
fmt . Println ( "Running as root. Please specify an unprivileged user to switch to, using the -u flag" )
}
return
os . Exit ( 1 )
}
uid , err := strconv . ParseInt ( userInfo . Uid , 10 , 32 )
// Convert group id and user id from string to int.
gid , err := strconv . Atoi ( userInfo . Gid )
if err != nil {
fmt . Println ( err )
return
os . Exit ( 1 )
}
gid, err := strconv . ParseInt ( userInfo . Gid , 10 , 32 )
uid, err := strconv . Atoi ( userInfo . Uid )
if err != nil {
fmt . Println ( err )
return
os . Exit ( 1 )
}
if uid == 0 {
fmt . Println ( "WARNING: running as root is not recommended!" )
}
// Unset supplementary group IDs.
err = syscall . Setgroups ( [ ] int { } )
if err != nil {
fmt . Println ( "Failed to unset supplementary group IDs: " + err . Error ( ) )
os . Exit ( 1 )
}
cerr , errno := C . setgid ( C . __gid_t ( gid ) )
if cerr != 0 {
log . Fatalln ( "Unable to set GID due to error:" , errno )
// Set group ID.
err = syscall . Setgid ( gid )
if err != nil {
fmt . Println ( "Failed to set group ID: " + err . Error ( ) )
os . Exit ( 1 )
}
cerr , errno = C . setuid ( C . __uid_t ( uid ) )
if cerr != 0 {
log . Fatalln ( "Unable to set UID due to error:" , errno )
// Set user ID.
err = syscall . Setuid ( uid )
if err != nil {
fmt . Println ( "Failed to set user ID: " + err . Error ( ) )
os . Exit ( 1 )
}
}