mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-10-01 03:26:35 -05:00
NAS: General request and logging improvements
This commit is contained in:
@@ -29,6 +29,7 @@ type Config struct {
|
||||
KeyPathDS string `xml:"keyPathDS"`
|
||||
APISecret string `xml:"apiSecret"`
|
||||
AllowDefaultDolphinKeys bool `xml:"allowDefaultDolphinKeys"`
|
||||
ServerName string `xml:"serverName,omitempty"`
|
||||
}
|
||||
|
||||
func GetConfig() Config {
|
||||
@@ -39,6 +40,7 @@ func GetConfig() Config {
|
||||
|
||||
var config Config
|
||||
config.AllowDefaultDolphinKeys = true
|
||||
config.ServerName = "WiiLink"
|
||||
|
||||
err = xml.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
@@ -65,7 +67,7 @@ func GetConfig() Config {
|
||||
enable := true
|
||||
config.EnableHTTPSExploitWii = &enable
|
||||
}
|
||||
|
||||
|
||||
if config.EnableHTTPSExploitDS == nil {
|
||||
enable := true
|
||||
config.EnableHTTPSExploitDS = &enable
|
||||
|
||||
40
gamestats/main.go
Normal file
40
gamestats/main.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package gamestats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
pool *pgxpool.Pool
|
||||
)
|
||||
|
||||
func StartServer() {
|
||||
// Get config
|
||||
config := common.GetConfig()
|
||||
|
||||
common.ReadGameList()
|
||||
|
||||
// Start SQL
|
||||
dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName)
|
||||
dbConf, err := pgxpool.ParseConfig(dbString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pool, err = pgxpool.ConnectConfig(ctx, dbConf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
logging.Info("GSTATS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
|
||||
}
|
||||
88
nas/https.go
88
nas/https.go
@@ -20,6 +20,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
|
||||
@@ -65,6 +66,15 @@ func startHTTPSProxy(config common.Config) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
setupRealTLS(privKeyPath, certsPath)
|
||||
// Reread the private key and certs on a regular interval
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(24 * time.Hour)
|
||||
setupRealTLS(privKeyPath, certsPath)
|
||||
}
|
||||
}()
|
||||
|
||||
if !(exploitWii || exploitDS) {
|
||||
// Only handle real TLS requests
|
||||
for {
|
||||
@@ -204,7 +214,7 @@ func startHTTPSProxy(config common.Config) {
|
||||
}...)
|
||||
|
||||
serverCertsRecordDS = append(serverCertsRecordDS, certDS...)
|
||||
|
||||
|
||||
serverCertsRecordDS = append(serverCertsRecordDS, []byte{
|
||||
byte(wiiCertLenDS >> 16),
|
||||
byte(wiiCertLenDS >> 8),
|
||||
@@ -224,7 +234,7 @@ func startHTTPSProxy(config common.Config) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logging.Info("NAS-TLS", "Receiving HTTPS request from", aurora.BrightCyan(conn.RemoteAddr()))
|
||||
// logging.Info("NAS-TLS", "Receiving HTTPS request from", aurora.BrightCyan(conn.RemoteAddr()))
|
||||
moduleName := "NAS-TLS:" + conn.RemoteAddr().String()
|
||||
|
||||
go handleTLS(moduleName, conn, nasAddr, privKeyPath, certsPath, serverCertsRecordWii, rsaKeyWii, serverCertsRecordDS, rsaKeyDS)
|
||||
@@ -262,10 +272,10 @@ func handleTLS(moduleName string, rawConn net.Conn, nasAddr string, privKeyPath
|
||||
0x00, 0x35, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00,
|
||||
0x00, 0x05, 0x00, 0x00, 0x04,
|
||||
}[index] {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if (index == 0x1D) {
|
||||
if index == 0x1D {
|
||||
macFn, cipher, clientCipher := handleWiiTLSHandshake(moduleName, conn, serverCertsRecordWii, rsaKeyWii)
|
||||
proxyConsoleTLS(moduleName, conn, nasAddr, VersionTLS10, macFn, cipher, clientCipher)
|
||||
return
|
||||
@@ -285,17 +295,17 @@ func handleTLS(moduleName string, rawConn net.Conn, nasAddr string, privKeyPath
|
||||
if helloBytes[index] != []byte{
|
||||
0x16, 0x03, 0x00, 0x00, 0x2F, 0x01, 0x00, 0x00, 0x2B, 0x03, 0x00,
|
||||
}[index] {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if (index == 0x0B) {
|
||||
if index == 0x0B {
|
||||
macFn, cipher, clientCipher := handleDSSSLHandshake(moduleName, conn, serverCertsRecordDS, rsaKeyDS)
|
||||
proxyConsoleTLS(moduleName, conn, nasAddr, VersionSSL30, macFn, cipher, clientCipher)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logging.Info(moduleName, "Forwarding client hello:", aurora.Cyan(fmt.Sprintf("% X ", helloBytes)))
|
||||
// logging.Info(moduleName, "Forwarding client hello:", aurora.Cyan(fmt.Sprintf("% X ", helloBytes)))
|
||||
handleRealTLS(moduleName, conn, nasAddr, privKeyPath, certsPath)
|
||||
}
|
||||
|
||||
@@ -486,7 +496,7 @@ func handleDSSSLHandshake(moduleName string, conn bufferedConn, serverCertsRecor
|
||||
finishHash := newFinishedHash(VersionSSL30)
|
||||
finishHash.Write(clientHello[0x5:0x34])
|
||||
|
||||
clientRandom := clientHello[0x0b:0x0b+0x20]
|
||||
clientRandom := clientHello[0x0b : 0x0b+0x20]
|
||||
|
||||
serverHello := []byte{0x16, 0x03, 0x00, 0x00, 0x2A, 0x02, 0x00, 0x00, 0x26, 0x03, 0x00}
|
||||
|
||||
@@ -715,7 +725,7 @@ func proxyConsoleTLS(moduleName string, conn bufferedConn, nasAddr string, versi
|
||||
return
|
||||
}
|
||||
|
||||
if (buf[1] != 0x03 || (version == VersionTLS10 && buf[2] != 0x01) || (version == VersionSSL30 && buf[2] != 0x00)) {
|
||||
if buf[1] != 0x03 || (version == VersionTLS10 && buf[2] != 0x01) || (version == VersionSSL30 && buf[2] != 0x00) {
|
||||
logging.Error(moduleName, "Invalid TLS version")
|
||||
return
|
||||
}
|
||||
@@ -758,6 +768,36 @@ func proxyConsoleTLS(moduleName string, conn bufferedConn, nasAddr string, versi
|
||||
}
|
||||
}
|
||||
|
||||
var realTLSConfig *tls.Config
|
||||
|
||||
func setupRealTLS(privKeyPath string, certsPath string) {
|
||||
// Read server key and certs
|
||||
|
||||
serverKey, err := os.ReadFile(privKeyPath)
|
||||
if err != nil {
|
||||
logging.Error("NAS-TLS", "Failed to read server key:", err)
|
||||
return
|
||||
}
|
||||
|
||||
serverCerts, err := os.ReadFile(certsPath)
|
||||
if err != nil {
|
||||
logging.Error("NAS-TLS", "Failed to read server certs:", err)
|
||||
return
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(serverCerts, serverKey)
|
||||
if err != nil {
|
||||
logging.Error("NAS-TLS", "Failed to parse server certs:", err)
|
||||
return
|
||||
}
|
||||
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
realTLSConfig = &config
|
||||
}
|
||||
|
||||
// handleRealTLS handles the TLS request legitimately using crypto/tls
|
||||
func handleRealTLS(moduleName string, conn net.Conn, nasAddr string, privKeyPath string, certsPath string) {
|
||||
// Recover from panics
|
||||
@@ -767,30 +807,13 @@ func handleRealTLS(moduleName string, conn net.Conn, nasAddr string, privKeyPath
|
||||
}
|
||||
}()
|
||||
|
||||
// Read server key and certs
|
||||
// TODO: Cache this
|
||||
serverKey, err := os.ReadFile(privKeyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if realTLSConfig == nil {
|
||||
return
|
||||
}
|
||||
|
||||
serverCerts, err := os.ReadFile(certsPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tlsConn := tls.Server(conn, realTLSConfig)
|
||||
|
||||
cert, err := tls.X509KeyPair(serverCerts, serverKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
tlsConn := tls.Server(conn, &config)
|
||||
|
||||
err = tlsConn.Handshake()
|
||||
err := tlsConn.Handshake()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -959,7 +982,7 @@ func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRand
|
||||
if version == VersionSSL30 {
|
||||
prf = prf30
|
||||
}
|
||||
|
||||
|
||||
seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
|
||||
seed = append(seed, serverRandom...)
|
||||
seed = append(seed, clientRandom...)
|
||||
@@ -1104,7 +1127,7 @@ func macMD5(version uint16, key []byte) macFunction {
|
||||
|
||||
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
|
||||
type tls10MAC struct {
|
||||
h hash.Hash
|
||||
h hash.Hash
|
||||
}
|
||||
|
||||
func (s tls10MAC) MAC(out, seq, header, data, extra []byte) []byte {
|
||||
@@ -1151,4 +1174,3 @@ func (s ssl30MAC) MAC(out, seq, header, data []byte, extra []byte) []byte {
|
||||
s.h.Write(out)
|
||||
return s.h.Sum(out[:0])
|
||||
}
|
||||
|
||||
|
||||
101
nas/main.go
101
nas/main.go
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"wwfc/api"
|
||||
"wwfc/common"
|
||||
"wwfc/gamestats"
|
||||
"wwfc/logging"
|
||||
"wwfc/nhttp"
|
||||
"wwfc/sake"
|
||||
@@ -20,6 +21,8 @@ import (
|
||||
var (
|
||||
ctx = context.Background()
|
||||
pool *pgxpool.Pool
|
||||
|
||||
serverName string
|
||||
)
|
||||
|
||||
func StartServer() {
|
||||
@@ -38,6 +41,8 @@ func StartServer() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
serverName = config.ServerName
|
||||
|
||||
address := *config.NASAddress + ":" + config.NASPort
|
||||
|
||||
if config.EnableHTTPS {
|
||||
@@ -49,6 +54,7 @@ func StartServer() {
|
||||
}
|
||||
|
||||
var regexSakeHost = regexp.MustCompile(`^([a-z\-]+\.)?sake\.gs\.`)
|
||||
var regexGamestatsHost = regexp.MustCompile(`^([a-z\-]+\.)?gamestats2?\.gs\.`)
|
||||
var regexStage1URL = regexp.MustCompile(`^/w([0-9])$`)
|
||||
|
||||
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -59,6 +65,13 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for *.gamestats(2).gs.* or gamestats(2).gs.*
|
||||
if regexGamestatsHost.MatchString(r.Host) {
|
||||
// Redirect to the gamestats server
|
||||
gamestats.HandleRequest(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
moduleName := "NAS:" + r.RemoteAddr
|
||||
|
||||
// Handle conntest server
|
||||
@@ -67,6 +80,37 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle DWC auth requests
|
||||
if r.URL.String() == "/ac" || r.URL.String() == "/pr" || r.URL.String() == "/download" {
|
||||
handleAuthRequest(moduleName, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle /nastest.jsp
|
||||
if r.URL.Path == "/nastest.jsp" {
|
||||
handleNASTest(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for /payload
|
||||
if strings.HasPrefix(r.URL.String(), "/payload") {
|
||||
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
|
||||
handlePayloadRequest(moduleName, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Stage 1
|
||||
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
|
||||
val, err := strconv.Atoi(match[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logging.Info("NAS", "Get stage 1:", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
|
||||
downloadStage1(w, val)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for /api/groups
|
||||
if r.URL.Path == "/api/groups" {
|
||||
api.HandleGroups(w, r)
|
||||
@@ -97,43 +141,42 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if r.URL.String() == "/ac" || r.URL.String() == "/pr" || r.URL.String() == "/download" {
|
||||
handleAuthRequest(moduleName, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for /payload
|
||||
if strings.HasPrefix(r.URL.String(), "/payload") {
|
||||
handlePayloadRequest(moduleName, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Stage 1
|
||||
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
|
||||
val, err := strconv.Atoi(match[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
downloadStage1(w, val)
|
||||
return
|
||||
}
|
||||
|
||||
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
|
||||
replyHTTPError(w, 404, "404 Not Found")
|
||||
}
|
||||
|
||||
func replyHTTPError(w http.ResponseWriter, errorCode int, errorString string) {
|
||||
response := "<html>\n"
|
||||
response += "<head><title>" + errorString + "</title></head>\n"
|
||||
response += "<body>\n"
|
||||
response += "<center><h1>" + errorString + "</h1></center>\n"
|
||||
response += "<hr><center>WiiLink</center>\n"
|
||||
response += "</body>\n"
|
||||
response += "</html>\n"
|
||||
response := "<html>\n" +
|
||||
"<head><title>" + errorString + "</title></head>\n" +
|
||||
"<body>\n" +
|
||||
"<center><h1>" + errorString + "</h1></center>\n" +
|
||||
"<hr><center>" + serverName + "</center>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n"
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Header().Set("Connection", "close")
|
||||
w.Header().Set("Server", "Nintendo")
|
||||
w.WriteHeader(errorCode)
|
||||
w.Write([]byte(response))
|
||||
}
|
||||
|
||||
func handleNASTest(w http.ResponseWriter) {
|
||||
response := "" +
|
||||
"<html>\n" +
|
||||
"<body>\n" +
|
||||
"</br>AuthServer is up</br> \n" +
|
||||
"\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n"
|
||||
|
||||
w.Header().Set("Content-Type", "text/html;charset=ISO-8859-1")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.Header().Set("Connection", "close")
|
||||
w.Header().Set("NODE", "authserver-service.authserver.svc.cluster.local")
|
||||
w.Header().Set("Server", "Nintendo")
|
||||
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte(response))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user