github.com/GuanceCloud/cliutils@v1.1.21/pipeline/ptinput/ipdb/iploc/iploc.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the MIT License.
     3  // This product includes software developed at Guance Cloud (https://www.guance.com/).
     4  // Copyright 2021-present Guance, Inc.
     5  
     6  // Package iploc implement ipdb.
     7  package iploc
     8  
     9  import (
    10  	"bufio"
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/GuanceCloud/cliutils/logger"
    17  	"github.com/GuanceCloud/cliutils/pipeline/ptinput/ipdb"
    18  	"github.com/GuanceCloud/cliutils/pipeline/ptinput/utils"
    19  	"github.com/ip2location/ip2location-go"
    20  )
    21  
    22  var _ ipdb.IPdb = (*IPloc)(nil)
    23  
    24  var l = logger.DefaultSLogger("iploc")
    25  
    26  type DB interface {
    27  	Get_all(ipaddress string) (ip2location.IP2Locationrecord, error)
    28  }
    29  
    30  var openDB = func(f string) (DB, error) {
    31  	db, err := ip2location.OpenDB(f)
    32  	return db, err
    33  }
    34  
    35  const (
    36  	FileSeparator = " "
    37  
    38  	ErrInvalidIP = "Invalid IP address"
    39  	ErrInvalidDB = "Invalid database file"
    40  
    41  	geoDefaultVal = "unknown"
    42  )
    43  
    44  func InitLog() {
    45  	l = logger.SLogger("iploc")
    46  }
    47  
    48  type IPloc struct {
    49  	db    DB
    50  	ispDB map[string]string
    51  }
    52  
    53  func (iploc *IPloc) Init(dataDir string, config map[string]string) {
    54  	ipdbDir := filepath.Join(dataDir, "ipdb", "iploc")
    55  	iplocFile := "iploc.bin"
    56  	ispFile := "ip2isp.txt"
    57  
    58  	if file, ok := config["iploc_file"]; ok {
    59  		if len(file) > 0 {
    60  			iplocFile = file
    61  		}
    62  	}
    63  
    64  	if file, ok := config["isp_file"]; ok {
    65  		if len(file) > 0 {
    66  			ispFile = file
    67  		}
    68  	}
    69  
    70  	if err := iploc.loadIPLib(filepath.Join(ipdbDir, iplocFile)); err != nil {
    71  		l.Warnf("iploc load ip lib error: %s", err.Error())
    72  	}
    73  
    74  	iploc.ispDB = map[string]string{}
    75  
    76  	if err := iploc.loadISP(filepath.Join(ipdbDir, ispFile)); err != nil {
    77  		l.Warnf("isp file load error: %s", err.Error())
    78  	}
    79  }
    80  
    81  func (iploc *IPloc) loadIPLib(f string) error {
    82  	if !utils.FileExist(f) {
    83  		l.Warnf("%v not found", f)
    84  		return nil
    85  	}
    86  
    87  	db, err := openDB(f)
    88  	if err != nil {
    89  		return err
    90  	} else {
    91  		iploc.db = db
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (iploc *IPloc) loadISP(f string) error {
    98  	m := make(map[string]string)
    99  
   100  	if !utils.FileExist(f) {
   101  		l.Warnf("%v not found", f)
   102  		return nil
   103  	}
   104  
   105  	fd, err := os.Open(filepath.Clean(f))
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	defer fd.Close() //nolint:errcheck,gosec
   111  
   112  	scanner := bufio.NewScanner(fd)
   113  	for scanner.Scan() {
   114  		contents := strings.Split(scanner.Text(), FileSeparator)
   115  		if len(contents) != 2 {
   116  			continue
   117  		}
   118  
   119  		ipBitStr, err := ipdb.ParseIPCIDR(contents[0])
   120  		if err != nil {
   121  			continue
   122  		}
   123  		m[ipBitStr] = contents[1]
   124  	}
   125  
   126  	if len(m) != 0 {
   127  		iploc.ispDB = m
   128  		l.Infof("found new %d rules", len(m))
   129  	} else {
   130  		l.Infof("no rules founded")
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func (iploc *IPloc) SearchIsp(ip string) string {
   137  	if len(iploc.ispDB) == 0 {
   138  		return "unknown"
   139  	}
   140  
   141  	for i := 32; i > 0; i-- {
   142  		ipCidr := fmt.Sprintf("%s/%v", ip, i)
   143  		ipBitStr, _ := ipdb.ParseIPCIDR(ipCidr)
   144  		if v, ok := iploc.ispDB[ipBitStr]; ok {
   145  			return v
   146  		}
   147  	}
   148  	return "unknown"
   149  }
   150  
   151  func (iploc *IPloc) Geo(ip string) (*ipdb.IPdbRecord, error) {
   152  	record := &ipdb.IPdbRecord{}
   153  	if iploc.db == nil {
   154  		return record, nil
   155  	}
   156  
   157  	r, err := iploc.get(ip)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	switch r.City {
   163  	case ErrInvalidIP, ErrInvalidDB:
   164  		r.City = geoDefaultVal
   165  	}
   166  
   167  	switch r.Region {
   168  	case ErrInvalidIP, ErrInvalidDB:
   169  		r.Region = geoDefaultVal
   170  	}
   171  
   172  	switch r.Country_short {
   173  	case ErrInvalidIP, ErrInvalidDB:
   174  		r.Country_short = geoDefaultVal
   175  	}
   176  
   177  	record.City = r.City
   178  	record.Region = r.Region
   179  	record.Country = r.Country_short
   180  
   181  	return record.CheckData(), err
   182  }
   183  
   184  func (iploc *IPloc) get(ip string) (*ip2location.IP2Locationrecord, error) {
   185  	if iploc.db == nil {
   186  		return nil, fmt.Errorf("GEO DB not set")
   187  	}
   188  
   189  	r, err := iploc.db.Get_all(ip)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	return &r, nil
   195  }