From 5d7f13e04e6de957e5aafc86c5c92423be118279 Mon Sep 17 00:00:00 2001 From: uan Date: Sun, 3 Aug 2025 13:43:07 +0200 Subject: [PATCH] fix conf --- go.mod | 2 +- main.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 135 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 68e91f0..f20619e 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module com.github/shlldev/miniws go 1.22.2 -require github.com/akamensky/argparse v1.4.0 // indirect +require github.com/akamensky/argparse v1.4.0 diff --git a/main.go b/main.go index ed1f994..cfa30bf 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,12 @@ package main import ( + "errors" "fmt" "log" "net/http" "os" + "slices" "strconv" "strings" "time" @@ -13,39 +15,65 @@ import ( ) const ( - PATH_ACCESSLOG string = "access.log" - PATH_ERRORLOG string = "error.log" - FLAGS_LOG_OPEN int = os.O_APPEND | os.O_WRONLY | os.O_CREATE - PERMS_LOG_OPEN os.FileMode = os.ModeType | os.ModePerm + PATH_ACCESSLOG string = "access.log" + PATH_ERRORLOG string = "error.log" + PATH_IPFILTER string = "ipfilter.conf" + PATH_USERAGENTFILTER string = "useragentfilter.conf" + FLAGS_LOG_OPEN int = os.O_APPEND | os.O_WRONLY | os.O_CREATE + FLAGS_CONFIG_OPEN int = os.O_RDONLY | os.O_CREATE + PERMS_LOG_OPEN os.FileMode = os.ModeType | os.ModePerm + PERMS_CONFIG_OPEN os.FileMode = os.ModeType | os.ModePerm + PERMS_MKDIR os.FileMode = os.ModeDir | os.ModePerm + FILTER_MODE_WHITELIST = 0 + FILTER_MODE_BLACKLIST = 1 ) -var _logFolder string = "" +var ( + logFolder string = "" + configFolder string = "" + ipFilter []string = make([]string, 0) + ipFilterMode = FILTER_MODE_WHITELIST + userAgentFilter []string = make([]string, 0) + userAgentFilterMode = FILTER_MODE_WHITELIST +) func main() { parser := argparse.NewParser("miniws", "") port := parser.String("p", "port", &argparse.Options{Default: "8040"}) - logFolder := parser.String("l", "logs-folder", &argparse.Options{Default: "logs"}) + _logFolder := parser.String("l", "logs-folder", &argparse.Options{Default: "logs"}) + _configFolder := parser.String("c", "config-folder", &argparse.Options{Default: "config"}) err := parser.Parse(os.Args) if err != nil { // In case of error print error and print usage // This can also be done by passing -h or --help flags fmt.Print(parser.Usage(err)) + return } - _logFolder = *logFolder + logFolder = *_logFolder + configFolder = *_configFolder - http.HandleFunc("/{resource...}", get) + parseIpFilter() + parseUserAgentFilter() + http.HandleFunc("/", get) log.Println("Server started on port " + *port) http.ListenAndServe(":"+*port, nil) } func get(writer http.ResponseWriter, req *http.Request) { + + respStatusCode := http.StatusOK + + if !isIpValid(req.RemoteAddr) || !isUserAgentValid(req.UserAgent()) { + writer.WriteHeader(http.StatusForbidden) + return + } + fetchedData, fetchErr := fetchFileContents(req.URL.Path) sentBytes := 0 - respStatusCode := http.StatusOK if logIfError(fetchErr) { respStatusCode = http.StatusNotFound @@ -102,22 +130,22 @@ func logAccess( out := fmt.Sprintf("%v %v %v [%v] \"%v\" %v %v \"%v\" \"%v\"\n", remoteAddr, identifier, authuser, timestamp, request, status, bytesSent, referer, user_agent, ) - os.Mkdir(_logFolder, os.ModeDir|os.ModePerm) - file, err := os.OpenFile(ensureSlashSuffix(_logFolder)+PATH_ACCESSLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) + os.Mkdir(logFolder, os.ModeDir|os.ModePerm) + file, err := os.OpenFile(ensureSlashSuffix(logFolder)+PATH_ACCESSLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) if err != nil { - log.Println("couldn't open log access file at", ensureSlashSuffix(_logFolder)+PATH_ACCESSLOG) + log.Println("couldn't open log access file at", ensureSlashSuffix(logFolder)+PATH_ACCESSLOG) } defer file.Close() file.WriteString(out) } func logError(str string) { - os.Mkdir(_logFolder, os.ModeDir|os.ModePerm) - file, err := os.OpenFile(ensureSlashSuffix(_logFolder)+PATH_ERRORLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) + os.Mkdir(logFolder, PERMS_MKDIR) + file, err := os.OpenFile(ensureSlashSuffix(logFolder)+PATH_ERRORLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) if err != nil { - log.Println("couldn't open log error file at", ensureSlashSuffix(_logFolder)+PATH_ERRORLOG) + log.Println("couldn't open log error file at", ensureSlashSuffix(logFolder)+PATH_ERRORLOG) } defer file.Close() file.WriteString(str + "\n") @@ -137,3 +165,94 @@ func getOrDash(str string) string { func ensureSlashSuffix(str string) string { return strings.TrimSuffix(str, "/") + "/" } + +func isIpValid(ip string) bool { + ip = strings.Split(ip, ":")[0] // remove port + switch ipFilterMode { + case FILTER_MODE_WHITELIST: + return slices.Contains(ipFilter, ip) + case FILTER_MODE_BLACKLIST: + return !slices.Contains(ipFilter, ip) + default: + return false + } +} + +func isUserAgentValid(userAgent string) bool { + switch userAgentFilterMode { + case FILTER_MODE_WHITELIST: + return slices.Contains(userAgentFilter, userAgent) + case FILTER_MODE_BLACKLIST: + return !slices.Contains(userAgentFilter, userAgent) + default: + return false + } +} + +func parseIpFilter() { + os.Mkdir(configFolder, PERMS_MKDIR) + fileinfo, err := os.Stat(ensureSlashSuffix(configFolder) + PATH_IPFILTER) + + if errors.Is(err, os.ErrNotExist) { + os.Create(ensureSlashSuffix(configFolder) + PATH_IPFILTER) + } + if fileinfo.Size() == 0 { // empty config + ipFilterMode = FILTER_MODE_BLACKLIST + ipFilter = make([]string, 0) + return + } + ipFilterContent, err := os.ReadFile(ensureSlashSuffix(configFolder) + PATH_IPFILTER) + + if logIfError(err) { + return + } + + ipFilterLines := strings.Split(string(ipFilterContent), "\n") + + _ipFilterMode := ipFilterLines[0] + + switch _ipFilterMode { + case "allow": + ipFilterMode = FILTER_MODE_WHITELIST + case "deny": + ipFilterMode = FILTER_MODE_BLACKLIST + default: + logError("invalid ip filter mode, use allow|deny") + } + + ipFilter = ipFilterLines[1:] + +} + +func parseUserAgentFilter() { + os.Mkdir(configFolder, PERMS_MKDIR) + fileinfo, err := os.Stat(ensureSlashSuffix(configFolder) + PATH_USERAGENTFILTER) + if errors.Is(err, os.ErrNotExist) { + os.Create(ensureSlashSuffix(configFolder) + PATH_USERAGENTFILTER) + } + if fileinfo.Size() == 0 { // empty config + userAgentFilterMode = FILTER_MODE_BLACKLIST + userAgentFilter = make([]string, 0) + return + } + + userAgentFilterContent, err := os.ReadFile(ensureSlashSuffix(configFolder) + PATH_USERAGENTFILTER) + + if logIfError(err) { + return + } + + userAgentFilterLines := strings.Split(string(userAgentFilterContent), "\n") + _userAgentFilterMode := userAgentFilterLines[0] + + println(len(userAgentFilterLines)) + switch _userAgentFilterMode { + case "allow": + userAgentFilterMode = FILTER_MODE_WHITELIST + case "deny": + userAgentFilterMode = FILTER_MODE_BLACKLIST + default: + logError("invalid userAgent filter mode, use allow|deny") + } + userAgentFilter = userAgentFilterLines[1:] +}