1
0

parselog.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package ovpm
  2. import (
  3. "bufio"
  4. "io"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. // clEntry reprsents a parsed entry that is present on OpenVPN
  10. // log section CLIENT LIST.
  11. type clEntry struct {
  12. CommonName string `json:"common_name"`
  13. RealAddress string `json:"real_address"`
  14. BytesReceived uint64 `json:"bytes_received"`
  15. BytesSent uint64 `json:"bytes_sent"`
  16. ConnectedSince time.Time `json:"connected_since"`
  17. }
  18. // rtEntry reprsents a parsed entry that is present on OpenVPN
  19. // log section ROUTING TABLE.
  20. type rtEntry struct {
  21. VirtualAddress string `json:"virtual_address"`
  22. CommonName string `json:"common_name"`
  23. RealAddress string `json:"real_address"`
  24. LastRef time.Time `json:"last_ref"`
  25. }
  26. // parseStatusLog parses the received OpenVPN status log file.
  27. // And then returns the parsed client information.
  28. func parseStatusLog(f io.Reader) ([]clEntry, []rtEntry) {
  29. // Parsing stages.
  30. const stageCL int = 0
  31. const stageRT int = 1
  32. const stageFin int = 2
  33. // Parsing variables.
  34. var currStage int
  35. var skipFor int
  36. var cl []clEntry
  37. var rt []rtEntry
  38. // Scan and parse the file by dividing it into chunks.
  39. scanner, skipFor := bufio.NewScanner(f), 3
  40. for lc := 0; scanner.Scan(); lc++ {
  41. if skipFor > 0 {
  42. skipFor--
  43. continue
  44. }
  45. txt := scanner.Text()
  46. switch currStage {
  47. case stageCL:
  48. if strings.Contains(txt, "ROUTING TABLE") {
  49. currStage = stageRT
  50. skipFor = 1
  51. continue
  52. }
  53. dat := strings.Split(txt, ",")
  54. cl = append(cl, clEntry{
  55. CommonName: trim(dat[0]),
  56. RealAddress: trim(dat[1]),
  57. BytesReceived: stoui64(trim(dat[2])),
  58. BytesSent: stoui64(trim(dat[3])),
  59. ConnectedSince: stodt(trim(dat[4])),
  60. })
  61. case stageRT:
  62. if strings.Contains(txt, "GLOBAL STATS") {
  63. currStage = stageFin
  64. break
  65. }
  66. dat := strings.Split(txt, ",")
  67. rt = append(rt, rtEntry{
  68. VirtualAddress: trim(dat[0]),
  69. CommonName: trim(dat[1]),
  70. RealAddress: trim(dat[2]),
  71. LastRef: stodt(trim(dat[3])),
  72. })
  73. }
  74. }
  75. if err := scanner.Err(); err != nil {
  76. panic(err)
  77. }
  78. return cl, rt
  79. }
  80. // stoi64 converts string to uint64.
  81. func stoui64(s string) uint64 {
  82. i, err := strconv.ParseInt(s, 0, 64)
  83. if err != nil {
  84. panic(err)
  85. }
  86. return uint64(i)
  87. }
  88. // stodt converts string to date time.
  89. func stodt(s string) time.Time {
  90. t, err := time.ParseInLocation(time.ANSIC, s, time.Local)
  91. if err != nil {
  92. panic(err)
  93. }
  94. return t
  95. }
  96. // trim will trim all leading and trailing whitespace from the s.
  97. func trim(s string) string {
  98. return strings.TrimSpace(s)
  99. }