A More Secure Internet Connection for Your Home https://fen.gg
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

219 lines
5.6 KiB

  1. package model
  2. //
  3. // Fengg Security Gateway Server Application
  4. // Copyright (C) 2020 Lukas Matt <support@fen.gg>
  5. //
  6. // This program is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. //
  18. import (
  19. "net"
  20. "time"
  21. "errors"
  22. "strings"
  23. "sync"
  24. "fmt"
  25. "tea.fen.gg/fengg/server/types"
  26. "tea.fen.gg/fengg/server/utils"
  27. "github.com/oschwald/geoip2-golang"
  28. "tea.fen.gg/fengg/server/config"
  29. "github.com/jmoiron/sqlx"
  30. _ "github.com/lib/pq"
  31. )
  32. const (
  33. IPInformationNamedInsertTmpl = `
  34. INSERT INTO ip_information (
  35. ip, mac, reverse_dns, net_bios, created_at, updated_at,
  36. country, european_union, anonymous_proxy, satellite_provider
  37. ) VALUES (
  38. :ip, :mac, :reverse_dns, :net_bios, :created_at, :updated_at,
  39. :country, :european_union, :anonymous_proxy, :satellite_provider
  40. ) RETURNING id;`
  41. IPInformationNamedUpdateTmpl = `
  42. UPDATE ip_information
  43. SET
  44. reverse_dns=:reverse_dns, net_bios=:net_bios, updated_at=now(),
  45. country=:country, european_union=:european_union,
  46. anonymous_proxy=:anonymous_proxy, satellite_provider=:satellite_provider
  47. WHERE %s;`
  48. IPInformationQueryTmpl = `SELECT * FROM ip_information WHERE %s;`
  49. )
  50. type IPInformation struct {
  51. ID uint `db:"id" json:"id"`
  52. CreatedAt time.Time `db:"created_at" json:"createdAt"`
  53. UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
  54. IP types.IP `db:"ip" json:"ip"`
  55. MacAddress string `db:"mac" json:"macAddress"`
  56. ReverseDNS string `db:"reverse_dns" json:"reverseDNS"`
  57. NetBIOS string `db:"net_bios" json:"netBIOS"`
  58. Country string `db:"country" json:"country"`
  59. EuropeanUnion bool `db:"european_union" json:"europeanUnion"`
  60. AnonymousProxy bool `db:"anonymous_proxy" json:"anonymousProxy"`
  61. SatelliteProvider bool `db:"satellite_provider" json:"satelliteProvider"`
  62. }
  63. type IPInformations []IPInformation
  64. func NewIPInformation() *IPInformation {
  65. return &IPInformation{
  66. CreatedAt: time.Now(),
  67. UpdatedAt: time.Now(),
  68. }
  69. }
  70. func (info *IPInformation) Valid() bool {
  71. return info.IP.Raw != nil || info.ID > 0
  72. }
  73. func (info *IPInformation) Find() error {
  74. if !info.Valid() {
  75. return errors.New("we need at least an IP address or database ID")
  76. }
  77. db, err := sqlx.Connect(dbDriver, dbConnect)
  78. if err != nil {
  79. return err
  80. }
  81. defer db.Close()
  82. if info.IP.Raw != nil {
  83. return db.Get(info, fmt.Sprintf(IPInformationQueryTmpl, "ip=$1"), info.IP.String())
  84. }
  85. return db.Get(info, fmt.Sprintf(IPInformationQueryTmpl, "id=$1"), info.ID)
  86. }
  87. func (info *IPInformation) CreateOrUpdate() error {
  88. if !info.Valid() {
  89. return errors.New("we need at least an IP address or database ID")
  90. }
  91. db, err := sqlx.Connect(dbDriver, dbConnect)
  92. if err != nil {
  93. return err
  94. }
  95. defer db.Close()
  96. if info.ID <= 0 {
  97. err = db.Get(&info.ID, "SELECT id FROM ip_information WHERE ip=$1;", info.IP.String())
  98. }
  99. if err != nil {
  100. logger.Debug().Err(err).Msg("no ip_information found")
  101. // if it doesn't exist try to add it first
  102. rows, err := db.NamedQuery(IPInformationNamedInsertTmpl, info)
  103. if err != nil {
  104. return err
  105. }
  106. defer rows.Close()
  107. for rows.Next() {
  108. err = rows.Scan(&(info.ID))
  109. if err != nil {
  110. return err
  111. }
  112. }
  113. return nil
  114. }
  115. _, err = db.NamedExec(fmt.Sprintf(IPInformationNamedUpdateTmpl, "id=:id"), info)
  116. return err
  117. }
  118. func (info *IPInformation) InternalNetwork() bool {
  119. if info == nil {
  120. return false
  121. }
  122. var intfs NetworkInterfaces
  123. err := intfs.FindAll()
  124. if err != nil {
  125. logger.Fatal().Err(err).Msg("cannot fetch network interfaces from database")
  126. }
  127. for _, intf := range intfs {
  128. network := intf.Network()
  129. if network == nil || network.Network == nil {
  130. continue
  131. }
  132. if network.Network.Contains(info.IP.Raw) {
  133. return true
  134. }
  135. }
  136. return false
  137. }
  138. func (info *IPInformation) LookupNetBios() error {
  139. if !info.InternalNetwork() {
  140. return nil
  141. }
  142. name, err := utils.Nbtscan(info.IP.Raw)
  143. info.NetBIOS = name
  144. return err
  145. }
  146. func (info *IPInformation) LookupRDNSAndGeoIP() {
  147. waitGroup := new(sync.WaitGroup)
  148. waitGroup.Add(2)
  149. go func() {
  150. defer waitGroup.Done()
  151. lookups, err := net.LookupAddr(info.IP.String())
  152. if err != nil {
  153. logger.Debug().Err(err).Msg("cannot find reverse dns record")
  154. return
  155. }
  156. info.ReverseDNS = strings.Join(lookups, ",")
  157. }()
  158. go func() {
  159. defer waitGroup.Done()
  160. geodb, err := geoip2.Open(config.App.GeoIPDatabase)
  161. if err != nil {
  162. logger.Debug().Err(err).Msg("cannot open geoip database file")
  163. return
  164. }
  165. defer geodb.Close()
  166. record, err := geodb.Country(info.IP.Raw)
  167. if err != nil {
  168. logger.Debug().Err(err).Msg("cannot find record for ip address")
  169. return
  170. }
  171. info.Country = record.Country.IsoCode
  172. info.EuropeanUnion = record.Country.IsInEuropeanUnion
  173. info.AnonymousProxy = record.Traits.IsAnonymousProxy
  174. info.SatelliteProvider = record.Traits.IsSatelliteProvider
  175. }()
  176. waitGroup.Wait()
  177. }
  178. func (info *IPInformation) LookupMAC() error {
  179. if !info.InternalNetwork() {
  180. return nil
  181. }
  182. mac, err := utils.Arpscan(info.IP.Raw)
  183. info.MacAddress = mac.String()
  184. return err
  185. }