fix(server): guard access-log parser against malformed lines

GetXrayLogs split each Xray access-log line on whitespace and then read
fixed offsets — parts[1] for the timestamp and parts[i+1] after the "from",
"accepted" and "email:" markers — without checking the line had that many
fields. A truncated or malformed line (the logged destination is
attacker-influenced) indexed past the slice and panicked; the panel handler
returned a 500 via Gin's recovery.

Extract the per-line field parsing into parseAccessLogFields and length
guard every positional lookup so a short line yields a partial entry
instead of panicking.
This commit is contained in:
MHSanaei
2026-07-15 04:44:53 +02:00
parent a061a0ca87
commit 68a981c0c3
2 changed files with 84 additions and 25 deletions
+35 -25
View File
@@ -1132,6 +1132,40 @@ func (s *ServerService) GetLogs(count string, level string, syslog string) []str
return lines
}
// parseAccessLogFields extracts the structured fields from one Xray access-log
// line. Lines are attacker-influenced (a client's requested destination lands in
// the log verbatim) and may be truncated, so every positional lookup is length
// guarded: a malformed line yields a partial entry rather than panicking.
func parseAccessLogFields(line string) LogEntry {
var entry LogEntry
parts := strings.Fields(line)
for i, part := range parts {
if i == 0 && len(parts) > 1 {
dateTime, err := time.ParseInLocation("2006/01/02 15:04:05.999999", parts[0]+" "+parts[1], time.Local)
if err != nil {
continue
}
entry.DateTime = dateTime.UTC()
}
if part == "from" && i+1 < len(parts) {
entry.FromAddress = strings.TrimLeft(parts[i+1], "/")
} else if part == "accepted" && i+1 < len(parts) {
entry.ToAddress = strings.TrimLeft(parts[i+1], "/")
} else if strings.HasPrefix(part, "[") {
entry.Inbound = part[1:]
} else if strings.HasSuffix(part, "]") {
entry.Outbound = part[:len(part)-1]
} else if part == "email:" && i+1 < len(parts) {
entry.Email = parts[i+1]
}
}
return entry
}
func (s *ServerService) GetXrayLogs(
count string,
filter string,
@@ -1176,31 +1210,7 @@ func (s *ServerService) GetXrayLogs(
continue
}
var entry LogEntry
parts := strings.Fields(line)
for i, part := range parts {
if i == 0 {
dateTime, err := time.ParseInLocation("2006/01/02 15:04:05.999999", parts[0]+" "+parts[1], time.Local)
if err != nil {
continue
}
entry.DateTime = dateTime.UTC()
}
if part == "from" {
entry.FromAddress = strings.TrimLeft(parts[i+1], "/")
} else if part == "accepted" {
entry.ToAddress = strings.TrimLeft(parts[i+1], "/")
} else if strings.HasPrefix(part, "[") {
entry.Inbound = part[1:]
} else if strings.HasSuffix(part, "]") {
entry.Outbound = part[:len(part)-1]
} else if part == "email:" {
entry.Email = parts[i+1]
}
}
entry := parseAccessLogFields(line)
if logEntryContains(line, freedoms) {
if showDirect == "false" {