Golang实现RDAP到gRPC的协议转换

Golang实现RDAP到gRPC的协议转换 大家好, 希望大家都一切顺利。 有人能帮我将 github.com/openrdap/rdap 代码转换为 gRPC 吗? 我目前使用这段代码通过 RDAP 从网络中提取数据,现在我想做同样的事情,但使用 gRPC,但我对如何开始使用 gRPC 没有任何头绪。 请给我一个关于如何将此 RDAP 代码转换为 gRPC 的演示。

package main

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/openrdap/rdap"
)

const IPSET_FILE = "output.json"

var blockips BlockIP

// var blockips = NewBlockIP(IPSET_INTVAL)
type AnaylsisResult map[string]bool

type BlockIP map[string][]string

type NetworkInfo struct {
	Ip       string `json:"ip"`
	Hostname string `json:"hostname"`
	Reverse  string `json:"reverse"`
}

//ArinInfo data
type ArinInfo struct {
	Name         string   `json:"name,omitempty"`
	Handle       string   `json:"handle,omitempty"`
	Parent       string   `json:"parent,omitempty"`
	Type         string   `json:"type,omitempty"`
	Range        string   `json:"range,omitempty"`
	Cidr         string   `json:"cidr,omitempty"`
	Status       []string `json:"status,omitempty"`
	Registration string   `json:"registration,omitempty"`
	Updated      string   `json:"updated,omitempty"`
}

//OrgnizationInfo data
type OrgnizationInfo struct {
	Name         string `json:"name,omitempty"`
	Handle       string `json:"handle,omitempty"`
	Street       string `json:"street,omitempty"`
	City         string `json:"city,omitempty"`
	Province     string `json:"province,omitempty"`
	Postal       string `json:"postal,omitempty"`
	Country      string `json:"country,omitempty"`
	Registration string `json:"registration,omitempty"`
	Updated      string `json:"updated,omitempty"`
}

//ContactInfo data
type ContactInfo struct {
	Name         string `json:"name,omitempty"`
	Handle       string `json:"handle,omitempty"`
	Company      string `json:"company,omitempty"`
	Street       string `json:"street,omitempty"`
	City         string `json:"city,omitempty"`
	Province     string `json:"province,omitempty"`
	Postal       string `json:"postal,omitempty"`
	Country      string `json:"country,omitempty"`
	Registration string `json:"registration,omitempty"`
	Updated      string `json:"updated,omitempty"`
	Phone        string `json:"phone,omitempty"`
	Email        string `json:"email,omitempty"`
}

//Response data
type Response struct {
	Network     NetworkInfo     `json:"network,omitempty"`
	Arin        ArinInfo        `json:"arin,omitempty"`
	Orgnization OrgnizationInfo `json:"orgnization,omitempty"`
	Contact     ContactInfo     `json:"contact,omitempty"`
	Abuse       ContactInfo     `json:"abuse,omitempty"`
	Anaylsis    AnaylsisResult  `json:"anaylsis,omitempty"`
}

func init() {
	log.SetFlags(log.Lshortfile)
	// init blockip datasource
	// open blockip file
	f, e := os.OpenFile(IPSET_FILE, os.O_RDONLY, 0666)
	if e != nil {
		log.Println(e)
		return
	}
	blockips = NewBlockIP(f)

}

func main() {
	//router
	r := http.NewServeMux()
	//routes
	r.HandleFunc("/", reverseIpHandler)
	r.HandleFunc("/ip/", ipHandler)
	//http server
	http.ListenAndServe(":8080", r)
}

func NewResponse(ip string) (rsp *Response) {
	rsp = new(Response)
	// process
	rsp.parseNetWork(ip)
	rsp.Parse(ip)
	return
}

func (rsp *Response) parseNetWork(ip string) {
	// set default value
	rsp.Network = NetworkInfo{}
	rsp.Network.Ip = ip

	host, err := net.LookupAddr(ip)
	if err != nil || len(host) == 0 {
		log.Println(err, ip)
		return
	}

	revIP, err := net.LookupIP(host[0])
	if err != nil || len(revIP) == 0 {
		return
	}
	// update network value
	rsp.Network.Hostname = host[0]
	rsp.Network.Reverse = revIP[0].String()
}

func (rsp *Response) Parse(ip string) {
	// read whois information
	c := &rdap.Client{}
	rs, e := c.QueryIP(ip)
	if e != nil {
		log.Println(e)
		return
	}
	// arinfo
	rsp.Arin.Name = rs.Name
	rsp.Arin.Cidr = rs.Handle
	rsp.Arin.Handle = rs.Handle
	rsp.Arin.Parent = rs.ParentHandle
	rsp.Arin.Range = rs.StartAddress + "-" + rs.EndAddress
	rsp.Arin.Type = rs.Type
	// update registration and updated
	for _, v := range rs.Events {
		switch v.Action {
		case "registration":
			rsp.Arin.Registration = v.Date
		case "last changed":
			rsp.Arin.Updated = v.Date
		}
	}

	for _, ett := range rs.Entities {
		if ett.VCard == nil {
			continue
		}
		switch {
		// orgnization infomation
		case isExists(ett.Roles, "registrant"):
			rsp.Orgnization.Country = ett.VCard.Country()
			rsp.Orgnization.City = ett.VCard.ExtendedAddress()
			rsp.Orgnization.Handle = ett.Handle
			rsp.Orgnization.Name = ett.VCard.Name()
			rsp.Orgnization.Postal = ett.VCard.PostalCode()
			rsp.Orgnization.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Orgnization.Registration = v.Date
				case "last changed":
					rsp.Orgnization.Updated = v.Date
				}
			}
			rsp.Orgnization.Street = ett.VCard.StreetAddress()
		// abuse information
		case isExists(ett.Roles, "abuse"):
			rsp.Abuse.Country = ett.VCard.Country()
			rsp.Abuse.City = ett.VCard.ExtendedAddress()
			rsp.Abuse.Email = ett.VCard.Email()
			rsp.Abuse.Handle = ett.Handle
			rsp.Abuse.Name = ett.VCard.Name()
			rsp.Abuse.Phone = ett.VCard.Tel()
			rsp.Abuse.Postal = ett.VCard.PostalCode()
			rsp.Abuse.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Abuse.Registration = v.Date
				case "last changed":
					rsp.Abuse.Updated = v.Date
				}
			}
			rsp.Abuse.Street = ett.VCard.StreetAddress()
			fallthrough
		// contact
		case isExists(ett.Roles, "administrative"):
			rsp.Contact.City = ett.VCard.ExtendedAddress()
			rsp.Contact.Country = ett.VCard.Country()
			rsp.Contact.Email = ett.VCard.Email()
			rsp.Contact.Handle = ett.Handle
			rsp.Contact.Name = ett.VCard.Name()
			rsp.Contact.Phone = ett.VCard.Tel()
			rsp.Contact.Postal = ett.VCard.PostalCode()
			rsp.Contact.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Contact.Registration = v.Date
				case "last changed":
					rsp.Contact.Updated = v.Date
				}
			}
			rsp.Contact.Street = ett.VCard.StreetAddress()
		}
	}
}

func isExists(src []string, item string) (r bool) {
	for _, v := range src {
		if v == item {
			r = true
			break
		}
	}
	return
}

func getContent(ct string) (r string) {
	idx := strings.Index(ct, ":")
	r = strings.Trim(ct[idx+1:], " ")
	r = strings.Trim(r, "\n")
	return
}

func reverseIpHandler(w http.ResponseWriter, r *http.Request) {
	//reverse ip
	rip := getReverseIp(r)
	rsp := NewResponse(rip)
	e := json.NewEncoder(w).Encode(rsp)
	if e != nil {
		log.Println(e)
	}

}

func getReverseIp(r *http.Request) string {
	ff := r.Header.Get("CF-Connecting-IP")
	if ff != "" {
		return ff
	}
	//fall back to request's remote address
	ip := getIp(r.RemoteAddr)
	return ip
}

func getIp(remoteAddress string) string {
	i := strings.Index(remoteAddress, ":")
	return remoteAddress[0:i]
}

func ipHandler(w http.ResponseWriter, r *http.Request) {
	//ip
	ip, err := getIpParam(r)
	if err != nil {
		log.Println(err)
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	rsp := NewResponse(ip)
	// anaylsis
	rsp.Anaylsis = blockips.Anaylsis(ip)

	e := json.NewEncoder(w).Encode(rsp)
	if e != nil {
		log.Println(e)
	}
}

func getIpParam(r *http.Request) (string, error) {
	//url path: /ip/:ip
	ip := r.URL.Path[4:]
	i := strings.Index(ip, "/")
	if i == -1 {
		return ip, nil
	} else {
		return "", errors.New("Failed to get ip parameter!")
	}
}

func NewBlockIP(f io.Reader) (bip BlockIP) {
	bip = make(BlockIP)
	bip.load(f)
	return
}

func (bip *BlockIP) load(f io.Reader) {
	dc := json.NewDecoder(f)
	e := dc.Decode(bip)
	if e != nil {
		log.Println(e)
		return
	}
}

func (bip BlockIP) Anaylsis(ip string) (rs AnaylsisResult) {
	rs = make(AnaylsisResult)
	for k, v := range bip {
		// detect if ip in v
		rs[k] = false
		for _, va := range v {
			if va == ip {
				rs[k] = true
				break
			}
			// if v contains "/" in the last 3 pst
			if strings.Contains(va, "/") {
				if ipinet(ip, va) {
					rs[k] = true
					break
				}
				va = va[:len(va)-3]
			}

			// compare the ip value
			// when va greate than ip then break
			ipi, e := IPString2Long(ip)
			if e != nil {
				log.Println(ip, e)
			}
			ipv, e := IPString2Long(va)
			if e != nil {
				log.Println(va, e)
			}
			// log.Println(ipi, ipv, va)
			if ipv > ipi {
				break
			}
		}
	}
	return
}

func ipinet(ip string, cidr string) (r bool) {
	ipx, subnet, _ := net.ParseCIDR(cidr)
	ipa := net.ParseIP(ip)
	// if netip eq ip then check ip existing
	if subnet.IP.Equal(ipx) {
		r = subnet.Contains(ipa)
		return
	}
	r = ipa.Equal(ipx)
	return
}

func IPString2Long(ip string) (uint, error) {
	b := net.ParseIP(ip).To4()
	if b == nil {
		return 0, errors.New("invalid ipv4 format")
	}

	return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

更多关于Golang实现RDAP到gRPC的协议转换的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

好的,明白了。

好的,谢谢你的回答,兄弟。

更多关于Golang实现RDAP到gRPC的协议转换的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我正在抓取领英数据,这段代码是抓取项目的一部分。

从网络中提取数据

这非常模糊。什么样的数据?从什么网络?

@lutzhorn 兄弟,我能在 gRPC 场景下转换整个代码吗?这只是一个简单的 REST API 代码,用于保存被阻止的 IP 地址并从这些 IP 中提取数据。我可以用其他方式实现吗?

你的问题存在一些问题。

  • 本论坛可以自动格式化 Go 代码。请选中你的所有代码,然后点击编辑窗口顶部的 </> 按钮。
  • 如果你只是在这里倾倒你的完整代码,而不添加任何关于代码功能、实现方式以及你希望在转换为 gRPC 后实现什么目标的解释,你将不会得到太多帮助。
func main() {
    fmt.Println("hello world")
}

感谢您的指导。实际上,我正在使用这段代码通过RDAP从网络中提取数据。现在我想做同样的事情,但使用gRPC,不过我对如何开始使用gRPC毫无头绪。 如果您能帮忙,请不吝赐教。

根据您的代码来看,RDAP 用于读取 IP 的 WHOIS 信息。

// read whois information
c := &rdap.Client{}
rs, e := c.QueryIP(ip)
// use data from `rs` ...

gRPC 与 WHOIS 无关。您无法用 gRPC 替换 RDAP。

以下是使用gRPC实现RDAP协议转换的完整示例:

1. 首先定义protobuf协议文件 rdap.proto

syntax = "proto3";

package rdap;

option go_package = "./rdappb";

service RdapService {
  rpc GetIPInfo(IPRequest) returns (Response) {}
  rpc GetReverseIP(ReverseIPRequest) returns (Response) {}
}

message IPRequest {
  string ip = 1;
}

message ReverseIPRequest {
  // 空消息,从请求头获取IP
}

message NetworkInfo {
  string ip = 1;
  string hostname = 2;
  string reverse = 3;
}

message ArinInfo {
  string name = 1;
  string handle = 2;
  string parent = 3;
  string type = 4;
  string range = 5;
  string cidr = 6;
  repeated string status = 7;
  string registration = 8;
  string updated = 9;
}

message OrganizationInfo {
  string name = 1;
  string handle = 2;
  string street = 3;
  string city = 4;
  string province = 5;
  string postal = 6;
  string country = 7;
  string registration = 8;
  string updated = 9;
}

message ContactInfo {
  string name = 1;
  string handle = 2;
  string company = 3;
  string street = 4;
  string city = 5;
  string province = 6;
  string postal = 7;
  string country = 8;
  string registration = 9;
  string updated = 10;
  string phone = 11;
  string email = 12;
}

message AnalysisResult {
  map<string, bool> results = 1;
}

message Response {
  NetworkInfo network = 1;
  ArinInfo arin = 2;
  OrganizationInfo organization = 3;
  ContactInfo contact = 4;
  ContactInfo abuse = 5;
  AnalysisResult analysis = 6;
}

2. 生成gRPC代码:

protoc --go_out=. --go-grpc_out=. rdap.proto

3. gRPC服务器实现 server.go

package main

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/openrdap/rdap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"

	pb "your_module_path/rdappb"
)

const IPSET_FILE = "output.json"

var blockips BlockIP

type AnaylsisResult map[string]bool
type BlockIP map[string][]string

type RdapServer struct {
	pb.UnimplementedRdapServiceServer
}

func (s *RdapServer) GetIPInfo(ctx context.Context, req *pb.IPRequest) (*pb.Response, error) {
	ip := req.GetIp()
	if ip == "" {
		return nil, errors.New("IP address is required")
	}

	rsp := NewResponse(ip)
	return convertToGRPCResponse(rsp), nil
}

func (s *RdapServer) GetReverseIP(ctx context.Context, req *pb.ReverseIPRequest) (*pb.Response, error) {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, errors.New("no metadata found")
	}

	var ip string
	if cfIPs := md.Get("cf-connecting-ip"); len(cfIPs) > 0 {
		ip = cfIPs[0]
	} else {
		peer, ok := peer.FromContext(ctx)
		if !ok {
			return nil, errors.New("cannot get peer info")
		}
		addr := peer.Addr.String()
		if idx := strings.Index(addr, ":"); idx != -1 {
			ip = addr[:idx]
		}
	}

	if ip == "" {
		return nil, errors.New("cannot determine IP address")
	}

	rsp := NewResponse(ip)
	return convertToGRPCResponse(rsp), nil
}

func convertToGRPCResponse(rsp *Response) *pb.Response {
	grpcRsp := &pb.Response{
		Network: &pb.NetworkInfo{
			Ip:       rsp.Network.Ip,
			Hostname: rsp.Network.Hostname,
			Reverse:  rsp.Network.Reverse,
		},
		Arin: &pb.ArinInfo{
			Name:         rsp.Arin.Name,
			Handle:       rsp.Arin.Handle,
			Parent:       rsp.Arin.Parent,
			Type:         rsp.Arin.Type,
			Range:        rsp.Arin.Range,
			Cidr:         rsp.Arin.Cidr,
			Status:       rsp.Arin.Status,
			Registration: rsp.Arin.Registration,
			Updated:      rsp.Arin.Updated,
		},
		Organization: &pb.OrganizationInfo{
			Name:         rsp.Orgnization.Name,
			Handle:       rsp.Orgnization.Handle,
			Street:       rsp.Orgnization.Street,
			City:         rsp.Orgnization.City,
			Province:     rsp.Orgnization.Province,
			Postal:       rsp.Orgnization.Postal,
			Country:      rsp.Orgnization.Country,
			Registration: rsp.Orgnization.Registration,
			Updated:      rsp.Orgnization.Updated,
		},
		Contact: &pb.ContactInfo{
			Name:         rsp.Contact.Name,
			Handle:       rsp.Contact.Handle,
			Company:      rsp.Contact.Company,
			Street:       rsp.Contact.Street,
			City:         rsp.Contact.City,
			Province:     rsp.Contact.Province,
			Postal:       rsp.Contact.Postal,
			Country:      rsp.Contact.Country,
			Registration: rsp.Contact.Registration,
			Updated:      rsp.Contact.Updated,
			Phone:        rsp.Contact.Phone,
			Email:        rsp.Contact.Email,
		},
		Abuse: &pb.ContactInfo{
			Name:         rsp.Abuse.Name,
			Handle:       rsp.Abuse.Handle,
			Company:      rsp.Abuse.Company,
			Street:       rsp.Abuse.Street,
			City:         rsp.Abuse.City,
			Province:     rsp.Abuse.Province,
			Postal:       rsp.Abuse.Postal,
			Country:      rsp.Abuse.Country,
			Registration: rsp.Abuse.Registration,
			Updated:      rsp.Abuse.Updated,
			Phone:        rsp.Abuse.Phone,
			Email:        rsp.Abuse.Email,
		},
		Analysis: &pb.AnalysisResult{
			Results: rsp.Anaylsis,
		},
	}
	return grpcRsp
}

func main() {
	initBlockIP()

	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	s := grpc.NewServer()
	pb.RegisterRdapServiceServer(s, &RdapServer{})

	log.Printf("gRPC server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

func initBlockIP() {
	f, err := os.OpenFile(IPSET_FILE, os.O_RDONLY, 0666)
	if err != nil {
		log.Println(err)
		return
	}
	blockips = NewBlockIP(f)
}

// 保留原有的 Response 结构体和相关方法
type Response struct {
	Network     NetworkInfo     `json:"network,omitempty"`
	Arin        ArinInfo        `json:"arin,omitempty"`
	Orgnization OrgnizationInfo `json:"orgnization,omitempty"`
	Contact     ContactInfo     `json:"contact,omitempty"`
	Abuse       ContactInfo     `json:"abuse,omitempty"`
	Anaylsis    AnaylsisResult  `json:"anaylsis,omitempty"`
}

type NetworkInfo struct {
	Ip       string `json:"ip"`
	Hostname string `json:"hostname"`
	Reverse  string `json:"reverse"`
}

type ArinInfo struct {
	Name         string   `json:"name,omitempty"`
	Handle       string   `json:"handle,omitempty"`
	Parent       string   `json:"parent,omitempty"`
	Type         string   `json:"type,omitempty"`
	Range        string   `json:"range,omitempty"`
	Cidr         string   `json:"cidr,omitempty"`
	Status       []string `json:"status,omitempty"`
	Registration string   `json:"registration,omitempty"`
	Updated      string   `json:"updated,omitempty"`
}

type OrgnizationInfo struct {
	Name         string `json:"name,omitempty"`
	Handle       string `json:"handle,omitempty"`
	Street       string `json:"street,omitempty"`
	City         string `json:"city,omitempty"`
	Province     string `json:"province,omitempty"`
	Postal       string `json:"postal,omitempty"`
	Country      string `json:"country,omitempty"`
	Registration string `json:"registration,omitempty"`
	Updated      string `json:"updated,omitempty"`
}

type ContactInfo struct {
	Name         string `json:"name,omitempty"`
	Handle       string `json:"handle,omitempty"`
	Company      string `json:"company,omitempty"`
	Street       string `json:"street,omitempty"`
	City         string `json:"city,omitempty"`
	Province     string `json:"province,omitempty"`
	Postal       string `json:"postal,omitempty"`
	Country      string `json:"country,omitempty"`
	Registration string `json:"registration,omitempty"`
	Updated      string `json:"updated,omitempty"`
	Phone        string `json:"phone,omitempty"`
	Email        string `json:"email,omitempty"`
}

func NewResponse(ip string) *Response {
	rsp := &Response{}
	rsp.parseNetWork(ip)
	rsp.Parse(ip)
	rsp.Anaylsis = blockips.Anaylsis(ip)
	return rsp
}

func (rsp *Response) parseNetWork(ip string) {
	rsp.Network = NetworkInfo{}
	rsp.Network.Ip = ip

	host, err := net.LookupAddr(ip)
	if err != nil || len(host) == 0 {
		log.Println(err, ip)
		return
	}

	revIP, err := net.LookupIP(host[0])
	if err != nil || len(revIP) == 0 {
		return
	}
	rsp.Network.Hostname = host[0]
	rsp.Network.Reverse = revIP[0].String()
}

func (rsp *Response) Parse(ip string) {
	c := &rdap.Client{}
	rs, err := c.QueryIP(ip)
	if err != nil {
		log.Println(err)
		return
	}

	rsp.Arin.Name = rs.Name
	rsp.Arin.Cidr = rs.Handle
	rsp.Arin.Handle = rs.Handle
	rsp.Arin.Parent = rs.ParentHandle
	rsp.Arin.Range = rs.StartAddress + "-" + rs.EndAddress
	rsp.Arin.Type = rs.Type

	for _, v := range rs.Events {
		switch v.Action {
		case "registration":
			rsp.Arin.Registration = v.Date
		case "last changed":
			rsp.Arin.Updated = v.Date
		}
	}

	for _, ett := range rs.Entities {
		if ett.VCard == nil {
			continue
		}
		switch {
		case isExists(ett.Roles, "registrant"):
			rsp.Orgnization.Country = ett.VCard.Country()
			rsp.Orgnization.City = ett.VCard.ExtendedAddress()
			rsp.Orgnization.Handle = ett.Handle
			rsp.Orgnization.Name = ett.VCard.Name()
			rsp.Orgnization.Postal = ett.VCard.PostalCode()
			rsp.Orgnization.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Orgnization.Registration = v.Date
				case "last changed":
					rsp.Orgnization.Updated = v.Date
				}
			}
			rsp.Orgnization.Street = ett.VCard.StreetAddress()
		case isExists(ett.Roles, "abuse"):
			rsp.Abuse.Country = ett.VCard.Country()
			rsp.Abuse.City = ett.VCard.ExtendedAddress()
			rsp.Abuse.Email = ett.VCard.Email()
			rsp.Abuse.Handle = ett.Handle
			rsp.Abuse.Name = ett.VCard.Name()
			rsp.Abuse.Phone = ett.VCard.Tel()
			rsp.Abuse.Postal = ett.VCard.PostalCode()
			rsp.Abuse.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Abuse.Registration = v.Date
				case "last changed":
					rsp.Abuse.Updated = v.Date
				}
			}
			rsp.Abuse.Street = ett.VCard.StreetAddress()
			fallthrough
		case isExists(ett.Roles, "administrative"):
			rsp.Contact.City = ett.VCard.ExtendedAddress()
			rsp.Contact.Country = ett.VCard.Country()
			rsp.Contact.Email = ett.VCard.Email()
			rsp.Contact.Handle = ett.Handle
			rsp.Contact.Name = ett.VCard.Name()
			rsp.Contact.Phone = ett.VCard.Tel()
			rsp.Contact.Postal = ett.VCard.PostalCode()
			rsp.Contact.Province = ett.VCard.Region()
			for _, v := range ett.Events {
				switch v.Action {
				case "registration":
					rsp.Contact.Registration = v.Date
				case "last changed":
					rsp.Contact.Updated = v.Date
				}
			}
			rsp.Contact.Street = ett.VCard.StreetAddress()
		}
	}
}

func isExists(src []string, item string) bool {
	for _, v := range src {
		if v == item {
			return true
		}
	}
	return false
}

func NewBlockIP(f io.Reader) BlockIP {
	bip := make(BlockIP)
	dc := json.NewDecoder(f)
	if err := dc.Decode(&bip); err != nil {
		log.Println(err)
	}
	return bip
}

func (bip BlockIP) Anaylsis(ip string) AnaylsisResult {
	rs := make(AnaylsisResult)
	for k, v := range bip {
		rs[k] = false
		for _, va := range v {
			if va == ip {
				rs[k] = true
				break
			}
			if strings.Contains(va, "/") {
				if ipinet(ip, va) {
					rs[k] = true
					break
				}
				va = va[:len(va)-3]
			}

			ipi, e := IPString2Long(ip)
			if e != nil {
				log.Println(ip, e)
			}
			ipv, e := IPString2Long(va)
			if e != nil {
				log.Println(va, e)
			}
			if ipv > ipi {
				break
			}
		}
	}
	return rs
}

func ipinet(ip string, cidr string) bool {
	ipx, subnet, _ := net.ParseCIDR(cidr)
	ipa := net.ParseIP(ip)
	if subnet.IP.Equal(ipx) {
		return subnet.Contains(ipa)
	}
	return ipa.Equal(ipx)
}

func IPString2Long(ip string) (uint, error) {
	b := net.ParseIP(ip).To4()
	if b == nil {
		return 0, errors.New("invalid ipv4 format")
	}
	return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

4. gRPC客户端示例 client.go

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	pb "your_module_path/rdappb"
)

func main() {
	conn, err := grpc.Dial("localhost:50051", 
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithBlock(),
		grpc.WithTimeout(5*time.Second))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewRdapServiceClient(conn)

	// 示例1: 查询特定IP
	ctx1 := context.Background()
	ipReq := &pb.IPRequest{Ip: "8.8.8.8"}
	resp1, err := client.GetIPInfo(ctx1, ipReq)
	if err != nil {
		log.Fatalf("GetIPInfo failed: %v", err)
	}
	fmt.Printf("IP Info for %s:\n", ipReq.Ip)
	fmt.Printf("Hostname: %s\n", resp1.Network.Hostname)
	fmt.Printf("Organization: %s\n", resp1.Organization.Name)

	// 示例2: 获取反向IP(需要设置metadata)
	ctx2 := metadata.NewOutgoingContext(context.Background(), 
		metadata.Pairs("cf-connecting-ip", "8.8.4.4"))
	reverseReq := &pb.ReverseIPRequest{}
	resp2, err
回到顶部