avatar

Catalog
从代码中学习Go(一)

前言

前言是很重要的,前言可以知道,为什么要做这件事,为什么会有这篇博客。2月底到3月初的时候,进行某一个项目时,由于需要大量数据的运算与处理,Python速度过慢,而C写起来又很慢,为了效率(实在没效率),临时使用了静态编译的go语言来实现相应的功能需求,并在当时学习了一些go的基本使用手法。时间过了很久,很多当时学会的技巧也都忘的差不多了,本篇,本想着和shell篇一样,从源码的角度进行分析(本篇敏感字段仅有真实的Salt值,随便设置一个即可),以后对类似功能有需求时,可以有一些参考的价值。但又不完全一样,go不是shell,不是简单知道怎么用就行的。因此,本篇仅作为一个引导,并不会做到一个完全细致的分析。我会根据当时的需求,列出两份我之前写的能跑起来的代码(已脱敏),并罗列代码中用到的技术以及我当时查阅的一些资料。因为短期用不上Go,它也不是我主流使用的语言,并且大部分情况下,需要什么功能查询一下就好了,所以等到某一天,我又因为某些任务,开始编写go代码的时候,再将本篇的内容进行补充与扩展。建议以后进一步扩展文章内容时,先读完文末链接的2本书,并参考开源源码后,再进行适当补充。

需求分析

需求a

  1. 给定特定的盐值
  2. 生成所有IPv4地址(42亿)与加盐哈希(使用sha256)后的对应关系
  3. 根据哈希值前2位,将对应关系存在相应的csv文件中
  4. 例如哈希值前2位为FF,则将对应关系存在255.csv中
  5. 从0.csv~255.csv,共建立256个相应的csv文件

需求b

  1. 给定特定的盐值
  2. 从给定的csv文件/json文件中读取域名
  3. 生成所有域名与加盐哈希(使用sha256)后的对应关系
  4. 进行需求a的3~5步

应用技术

字符串操作

  1. CSDN:golang strconv Atoi Itoa 例子
  2. CSDN:golang 中 strings 包的 Replace 用法介绍
  3. CSDN:Go strings.Split函数
  4. Go语言中文网:strings包里面的Split函数的坑
  5. 简书:Go语言的string和byte slice之间的转换

Slice

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 结构定义:
type slice struct {
array unsafe.Pointer // 指向一个底层数组的指针
len int // 当前切片的长度
cap int // 当前切片的容量,满足cap >= len
}

// 特性:
1. 切片(slice)和数组类似,也是表示一个有序元素,但这个序列的长度可变
2. 切片是对底层数组一个连续片段的引用,所以是引用类型
3. 切片内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内
4. 切片本身是一个只读对象,其工作机制类似数组指针的一种封装
5. 多个切片可以指向同一个底层数组,实现了内存共享

// 使用:
mySlice := make([]type, len, cap) // 创建方式
mySlice1 := make([]int, 5) // 长度为5,元素初始为0
mySlice2 := make([]int, 5, 10) // 长度为5,元素初始为0,预留10个元素的空间
mySlice3 := []int{10, 20, 30, 40, 50} // 长度为5,[]内不能写容量,否则就成了数组而不是切片了

Map

  1. 简书:Go内建函数make及切片slice、映射map详解

sync.map

  1. 博客园:深度解密Go语言之sync.map

反射

  1. Go语言设计与实现:反射
  2. The Go Programming Language:通过reflect.Value修改值
  3. vimsky.com:reflect.New()用法及代码示例

Json解析

  1. StackOverFLow:Go Unmarshal reflect.Type got map[string] interface{}
  2. 博客园:Go的Json解析-Marshal与Unmarshal

哈希计算

  1. CSDN:Go sha256使用实例介绍

跨平台编译

  1. 知乎:Go交叉编译(跨平台编译)
  2. StackOverFlow:Go 1.7 Cross Compilation from Windows to Linux/Ubuntu

代码实现

需求a

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main

import (
"crypto/hmac"
"crypto/sha256"
"encoding/csv"
"encoding/hex"
"fmt"
"os"
"reflect"
"strconv"
"strings"
"sync"
)

func fatal(e error) {
if e != nil {
panic(e)
}
}

func calculate_hash(ip string) (ip_hash string) {

key := "AAAABBBBCCCCDDDDEEEE11112222333344445555++++----"
keyb := []byte(key)
ipb := []byte(ip)

mac := hmac.New(sha256.New, keyb)
mac.Write(ipb)
msgmac := mac.Sum(nil)
hash_code := strings.ToUpper(hex.EncodeToString(msgmac))
// fmt.Printf(hash_code)
return hash_code
}

func initial_syncmap(fp_map sync.Map) (ret_map sync.Map) {

for i := 0; i <= 255; i++ {
key := strconv.Itoa(i)
filename := "iptab_hmac256\\" + key + ".csv"
f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE, 0666)
fatal(err)
fp_map.Store(key, f)
}
return fp_map
}

func free_syncmap(fp_map sync.Map) {

for i := 0; i <= 255; i++ {
key := strconv.Itoa(i)
f, ok := fp_map.Load(key)
if ok == false {
fmt.Println("Nothing Find!")
}

f_elem := reflect.ValueOf(f).Elem()
f_addr := f_elem.Addr().Interface().(*os.File)
// fmt.Println(f_addr, reflect.TypeOf(f_addr))
var fp *os.File
fp = f_addr
fp.Close()
}
fmt.Println("Over!")
}

// 由于为了更方便的编写代码,这里仅过滤掉了不存在/不在公网使用的大段,尽管部分不存在/不在公网使用的的IP
// 也被计算了进去,但总体上,并不会对速度有太大的影响
func generate_and_writein(start_ip string, c chan int, fp_map sync.Map) {

ip_addr := []string{"1", "0", "0", "0"}
ip_addr[0] = start_ip
// store elements writed in csvfile
elements := make([]string, 2)

for {
num_3, _ := strconv.Atoi(ip_addr[3])
num_2, _ := strconv.Atoi(ip_addr[2])
num_1, _ := strconv.Atoi(ip_addr[1])

if num_3 < 255 {
num_3++
ip_addr[3] = strconv.Itoa(num_3)
ip_str := strings.Join(ip_addr, ".")
ip_hash := calculate_hash(ip_str)

str_hex_uid := ip_hash[0:2]
uid, err := hex.DecodeString(str_hex_uid)
fatal(err)
fmt.Println(uid[0], " ", ip_str, " ", ip_hash)

// Writing Data in .csv
str_uid := strconv.Itoa(int(uid[0]))
filename := str_uid
f, _ := fp_map.Load(filename)
// fmt.Println(f)
f_elem := reflect.ValueOf(f).Elem()
f_addr := f_elem.Addr().Interface().(*os.File)
var fp *os.File
fp = f_addr

elements[0] = ip_str
elements[1] = ip_hash
w := csv.NewWriter(fp)
w.Write(elements)
w.Flush()
continue

} else if num_2 < 255 {
ip_addr[3] = strconv.Itoa(0)
num_2++
ip_addr[2] = strconv.Itoa(num_2)
continue

} else if num_1 < 255 {
ip_addr[2] = strconv.Itoa(0)
num_1++
ip_addr[1] = strconv.Itoa(num_1)
continue

} else if num_1 == 255 && num_2 == 255 && num_3 == 255 {
break
}
}
}

func main() {

var fp_map sync.Map
fp_map = initial_syncmap(fp_map)

// multi go routine generate ip & hash and write in csvfile
c := make(chan int)
for i := 1; i <= 255; i++ {
if i == 10 || i == 127 || i == 256 {
continue
}
start_ip := strconv.Itoa(i)
go generate_and_writein(start_ip, c, fp_map)
}
wait := <-c
fmt.Println(wait)

free_syncmap(fp_map)
}

需求b

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 两份readCsv代码,总体相同
func readCsv(fp_map sync.Map) {
filename := "domain.csv"
f, err := os.Open(filename)
fatal(err)
defer f.Close()

r := csv.NewReader(f)
for {
row, err := r.Read()
fatal(err)
// end := len(row) - 1
domain := row[0]
// fmt.Println(domain)
calculateHash(fp_map, domain)
}
}

func readCsv(fp_map sync.Map) {
for i := 1574; i <= 3145; i++ {
prefix := strconv.Itoa(i)
filename := "origin_csv\\" + prefix + "_full.csv"
f, err := os.Open(filename)
if err == nil {
fmt.Println(filename)
r := csv.NewReader(f)
for {
row, err := r.Read()
if err != nil {
break
}
domain := row[0]
// fmt.Println(domain)
calculateHash(fp_map, domain)
}
f.Close()
}
}
}

// json稍微复杂一下,需要先定义一个包含json各个字段的结构体
type (
ixx_detail struct {
Hxxx string `json":hxxx"`
Poxx string `json":poxx"`
Paxx string `json":paxx"`
}

intellxxxxxx_info struct {
Type string `json":type"`
Alxxx bool `json":alxxx"`
Status string `json":status"`
Rixx string `json":rixx"`
Confixxxxx string `json":confixxxxx"`
Maxxxxxxx_type uint8 `json":maxxxxxxx_type"`
Maxxxxxxx_fxxxxx string `json":maxxxxxxx_fxxxxx"`
Camxxxxx string `json":camxxxxx"`
Cxxtxxl_type string `json":cxxtxxl_type"`
Hox bool `json":hox"`
Protoxxx string `json":protoxxx"`
First_sxxx uint64 `json":first_sxxx"`
Last_sxxx uint64 `json":last_sxxx"`
Ixx string `json":ixx"`
Ixx_detail ixx_detail `json":ixx_detail"`
Tags []string `json":tags"`
}
)

func read_and_write(fp_map sync.Map) {

// read json content in memory
file, err := os.Open("domain.json")
fatal(err)
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
json_str := scanner.Text()
json_bytes := []byte(json_str)
data := intellxxxxxx_info{}
err = json.Unmarshal(json_bytes, &data)
fatal(err)

// write content in csv file
// 1.get respondent file
str_hex_uid := data.Ioc[0:2]
uid, err := hex.DecodeString(str_hex_uid)
fatal(err)
str_uid := strconv.Itoa(int(uid[0]))
filename := str_uid
f, _ := fp_map.Load(filename)
f_elem := reflect.ValueOf(f).Elem()
f_addr := f_elem.Addr().Interface().(*os.File)
var fp *os.File
fp = f_addr
fp.Close()

// 2.prepare data write in csv
elements := make([]string, 16)
elements[0] = data.Type
if data.Alert {
elements[1] = "true"
} else {
elements[1] = ""
}

// w := csv.NewWriter(fp)
// w.Write(data)
// w.Flush()

// i++
// if i%50000 == 0 {
// fmt.Println("already checked: ", i)
// }
continue
}
}

参考链接

  1. Go语言设计与实现
  2. Go语言圣经(中文版)
  3. Go源码库
Author: cataLoc
Link: http://cata1oc.github.io/2019/02/25/%E4%BB%8E%E4%BB%A3%E7%A0%81%E4%B8%AD%E5%AD%A6%E4%B9%A0Go01/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶