Skip to content

Commit b3ef94c

Browse files
committed
Enhancement: Don't use external curl command to do http requests
1 parent 892c20a commit b3ef94c

8 files changed

Lines changed: 200 additions & 39 deletions

File tree

launcher/internal/executor/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import (
77
"github.com/luskaner/ageLANServer/common/executor"
88
launcherCommon "github.com/luskaner/ageLANServer/launcher-common"
99
"github.com/luskaner/ageLANServer/launcher-common/executor/exec"
10+
"github.com/luskaner/ageLANServer/launcher/internal/server/certStore"
1011
)
1112

1213
func RunSetUp(game string, mapIps mapset.Set[string], addUserCertData []byte, addLocalCertData []byte, backupMetadata bool, backupProfiles bool, mapCDN bool, exitAgentOnError bool) (result *exec.Result) {
14+
reloadSystemCertificates := false
1315
args := make([]string, 0)
1416
args = append(args, "setup")
1517
if game != "" {
@@ -29,10 +31,12 @@ func RunSetUp(game string, mapIps mapset.Set[string], addUserCertData []byte, ad
2931
}
3032
}
3133
if addLocalCertData != nil {
34+
reloadSystemCertificates = true
3235
args = append(args, "-l")
3336
args = append(args, base64.StdEncoding.EncodeToString(addLocalCertData))
3437
}
3538
if addUserCertData != nil {
39+
reloadSystemCertificates = true
3640
args = append(args, "-u")
3741
args = append(args, base64.StdEncoding.EncodeToString(addUserCertData))
3842
}
@@ -46,13 +50,19 @@ func RunSetUp(game string, mapIps mapset.Set[string], addUserCertData []byte, ad
4650
args = append(args, "-c")
4751
}
4852
result = exec.Options{File: common.GetExeFileName(false, common.LauncherConfig), Wait: true, Args: args, ExitCode: true}.Exec()
53+
if reloadSystemCertificates {
54+
certStore.ReloadSystemCertificates()
55+
}
4956
return
5057
}
5158

5259
func RunRevert(game string, unmapIPs bool, removeUserCert bool, removeLocalCert bool, restoreMetadata bool, restoreProfiles bool, unmapCDN bool) (result *exec.Result) {
5360
args := []string{launcherCommon.ConfigRevertCmd}
5461
args = append(args, RevertFlags(game, unmapIPs, removeUserCert, removeLocalCert, restoreMetadata, restoreProfiles, unmapCDN)...)
5562
result = exec.Options{File: common.GetExeFileName(false, common.LauncherConfig), Wait: true, Args: args, ExitCode: true}.Exec()
63+
if removeUserCert || removeLocalCert {
64+
certStore.ReloadSystemCertificates()
65+
}
5666
return
5767
}
5868

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//go:build !windows
2+
3+
package certStore
4+
5+
import (
6+
"crypto/x509"
7+
_ "unsafe"
8+
)
9+
10+
// TODO: Check on every minor version release if there is a better way to do it, or, at least, it is compatible
11+
12+
//go:linkname systemRoots crypto/x509.systemRoots
13+
var systemRoots *x509.CertPool
14+
15+
func ReloadSystemCertificates() {
16+
systemRoots, _ = loadSystemRoots()
17+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package certStore
2+
3+
// ReloadSystemCertificates No need to reload certificates as the validity is checked by the OS
4+
func ReloadSystemCertificates() {
5+
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Source: https://github.com/golang/go/blob/master/src/crypto/x509/root_linux.go
2+
// TODO: Check on every minor version release if there is a better way to do it, or, at least, update it
3+
4+
package certStore
5+
6+
// Possible certificate files; stop after finding one.
7+
var certFiles = []string{
8+
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
9+
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
10+
"/etc/ssl/ca-bundle.pem", // OpenSUSE
11+
"/etc/pki/tls/cacert.pem", // OpenELEC
12+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
13+
"/etc/ssl/cert.pem", // Alpine Linux
14+
}
15+
16+
// Possible directories with certificate files; all will be read.
17+
var certDirectories = []string{
18+
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
19+
"/etc/pki/tls/certs", // Fedora/RHEL
20+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Source: https://github.com/golang/go/blob/master/src/crypto/x509/root_unix.go
2+
// TODO: Check on every minor version release if there is a better way to do it, or, at least, update it.
3+
4+
//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || wasip1
5+
6+
package certStore
7+
8+
import (
9+
"crypto/x509"
10+
"io/fs"
11+
"os"
12+
"path/filepath"
13+
"reflect"
14+
"strings"
15+
)
16+
17+
const (
18+
// certFileEnv is the environment variable which identifies where to locate
19+
// the SSL certificate file. If set this overrides the system default.
20+
certFileEnv = "SSL_CERT_FILE"
21+
22+
// certDirEnv is the environment variable which identifies which directory
23+
// to check for SSL certificate files. If set this overrides the system default.
24+
// It is a colon separated list of directories.
25+
// See https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html.
26+
certDirEnv = "SSL_CERT_DIR"
27+
)
28+
29+
func loadSystemRoots() (*x509.CertPool, error) {
30+
roots := x509.NewCertPool()
31+
32+
files := certFiles
33+
if f := os.Getenv(certFileEnv); f != "" {
34+
files = []string{f}
35+
}
36+
37+
var firstErr error
38+
for _, file := range files {
39+
data, err := os.ReadFile(file)
40+
if err == nil {
41+
roots.AppendCertsFromPEM(data)
42+
break
43+
}
44+
if firstErr == nil && !os.IsNotExist(err) {
45+
firstErr = err
46+
}
47+
}
48+
49+
dirs := certDirectories
50+
if d := os.Getenv(certDirEnv); d != "" {
51+
// OpenSSL and BoringSSL both use ":" as the SSL_CERT_DIR separator.
52+
// See:
53+
// * https://golang.org/issue/35325
54+
// * https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html
55+
dirs = strings.Split(d, ":")
56+
}
57+
58+
for _, directory := range dirs {
59+
fis, err := readUniqueDirectoryEntries(directory)
60+
if err != nil {
61+
if firstErr == nil && !os.IsNotExist(err) {
62+
firstErr = err
63+
}
64+
continue
65+
}
66+
for _, fi := range fis {
67+
data, err := os.ReadFile(directory + "/" + fi.Name())
68+
if err == nil {
69+
roots.AppendCertsFromPEM(data)
70+
}
71+
}
72+
}
73+
74+
if firstErr != nil {
75+
return roots, nil
76+
}
77+
78+
rootsValue := reflect.ValueOf(roots)
79+
lenMethod := rootsValue.MethodByName("len")
80+
results := lenMethod.Call(nil)
81+
82+
if results[0].Int() > 0 {
83+
return roots, nil
84+
}
85+
86+
return nil, firstErr
87+
}
88+
89+
// readUniqueDirectoryEntries is like os.ReadDir but omits
90+
// symlinks that point within the directory.
91+
func readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) {
92+
files, err := os.ReadDir(dir)
93+
if err != nil {
94+
return nil, err
95+
}
96+
uniq := files[:0]
97+
for _, f := range files {
98+
if !isSameDirSymlink(f, dir) {
99+
uniq = append(uniq, f)
100+
}
101+
}
102+
return uniq, nil
103+
}
104+
105+
// isSameDirSymlink reports whether fi in dir is a symlink with a
106+
// target not containing a slash.
107+
func isSameDirSymlink(f fs.DirEntry, dir string) bool {
108+
if f.Type()&fs.ModeSymlink == 0 {
109+
return false
110+
}
111+
target, err := os.Readlink(filepath.Join(dir, f.Name()))
112+
return err == nil && !strings.Contains(target, "/")
113+
}

launcher/internal/server/httpClient.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

launcher/internal/server/server.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
commonExecutor "github.com/luskaner/ageLANServer/launcher-common/executor/exec"
1414
"golang.org/x/net/ipv4"
1515
"net"
16+
"net/http"
1617
"net/netip"
1718
"os"
1819
"path"
@@ -81,7 +82,15 @@ func GetExecutablePath(executable string) string {
8182
}
8283

8384
func LanServer(host string, insecureSkipVerify bool) bool {
84-
return HttpGet(fmt.Sprintf("https://%s/test", host), insecureSkipVerify) == common.ErrSuccess
85+
tr := &http.Transport{
86+
TLSClientConfig: TlsConfig(insecureSkipVerify),
87+
}
88+
client := &http.Client{Transport: tr}
89+
resp, err := client.Head(fmt.Sprintf("https://%s/test", host))
90+
if err != nil {
91+
return false
92+
}
93+
return resp.StatusCode == http.StatusOK
8594
}
8695

8796
func announcementConnections(multicastIPs []net.IP, ports []int) []*net.UDPConn {

launcher/internal/server/ssl.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,41 @@ package server
33
import (
44
"crypto/tls"
55
"crypto/x509"
6-
"fmt"
76
"github.com/luskaner/ageLANServer/common"
87
"github.com/luskaner/ageLANServer/launcher-common/executor/exec"
98
"net"
109
"os"
1110
"path/filepath"
1211
)
1312

13+
func TlsConfig(insecureSkipVerify bool) *tls.Config {
14+
return &tls.Config{
15+
InsecureSkipVerify: insecureSkipVerify,
16+
}
17+
}
18+
19+
func connectToServer(host string, insecureSkipVerify bool) *tls.Conn {
20+
conn, err := tls.Dial("tcp4", net.JoinHostPort(host, "443"), TlsConfig(insecureSkipVerify))
21+
if err != nil {
22+
return nil
23+
}
24+
return conn
25+
}
26+
1427
func CheckConnectionFromServer(host string, insecureSkipVerify bool) bool {
15-
// 22 exit code means the host could be accessed and ssl certificate was tested (if specified)
16-
return HttpGet(fmt.Sprintf("https://%s", host), insecureSkipVerify) == 22
28+
conn := connectToServer(host, insecureSkipVerify)
29+
if conn == nil {
30+
return false
31+
}
32+
defer func() {
33+
_ = conn.Close()
34+
}()
35+
return conn != nil
1736
}
1837

1938
func ReadCertificateFromServer(host string) *x509.Certificate {
20-
conf := &tls.Config{
21-
InsecureSkipVerify: true,
22-
}
23-
conn, err := tls.Dial("tcp4", net.JoinHostPort(host, "443"), conf)
24-
if err != nil {
39+
conn := connectToServer(host, true)
40+
if conn == nil {
2541
return nil
2642
}
2743
defer func() {

0 commit comments

Comments
 (0)