1 | 1 | | package main |
2 | 2 | | |
3 | 3 | | import ( |
| 4 | + | "bufio" |
| 5 | + | "encoding/json" |
| 6 | + | "flag" |
4 | 7 | | "fmt" |
| 8 | + | "io/ioutil" |
| 9 | + | "log" |
5 | 10 | | "net/http" |
6 | | - | "io/ioutil" |
7 | | - | "encoding/json" |
8 | | - | "flag" |
9 | | - | "bufio" |
10 | 11 | | "os" |
11 | 12 | | "strings" |
| 13 | + | "sync" |
| 14 | + | |
12 | 15 | | "github.com/logrusorgru/aurora" |
13 | 16 | | ) |
14 | 17 | | |
| skipped 9 lines |
24 | 27 | | func main() { |
25 | 28 | | |
26 | 29 | | var noCPEs bool |
27 | | - | flag.BoolVar(&noCPEs, "nc", false, "hide cpes") |
| 30 | + | flag.BoolVar(&noCPEs, "nc", false, "Hide CPEs") |
28 | 31 | | |
29 | 32 | | var noHostnames bool |
30 | | - | flag.BoolVar(&noHostnames, "nh", false, "hide hostnames") |
| 33 | + | flag.BoolVar(&noHostnames, "nh", false, "Hide hostnames") |
31 | 34 | | |
32 | 35 | | var noTags bool |
33 | | - | flag.BoolVar(&noTags, "nt", false, "hide tags") |
| 36 | + | flag.BoolVar(&noTags, "nt", false, "Hide tags") |
34 | 37 | | |
35 | 38 | | var noVulns bool |
36 | | - | flag.BoolVar(&noVulns, "nv", false, "hide vulnerabilities") |
| 39 | + | flag.BoolVar(&noVulns, "nv", false, "Hide vulnerabilities") |
37 | 40 | | |
38 | 41 | | var noColor bool |
39 | | - | flag.BoolVar(&noColor, "nocolor", false, "disable color in output") |
| 42 | + | flag.BoolVar(&noColor, "nocolor", false, "Disable color in output") |
| 43 | + | |
| 44 | + | var jsonFile string |
| 45 | + | flag.StringVar(&jsonFile, "json", "", "Save output to JSON format") |
40 | 46 | | |
41 | 47 | | flag.Parse() |
42 | 48 | | |
| skipped 13 lines |
56 | 62 | | } |
57 | 63 | | |
58 | 64 | | channel := make(chan Response) |
59 | | - | for _, ip := range ips { |
60 | | - | go getData(ip, channel) |
| 65 | + | var wg sync.WaitGroup |
| 66 | + | |
| 67 | + | for i := 0; i < len(ips); i++ { |
| 68 | + | wg.Add(1) |
| 69 | + | |
| 70 | + | i := i |
| 71 | + | |
| 72 | + | go func() { |
| 73 | + | defer wg.Done() |
| 74 | + | jsonData := getData(ips[i]) |
| 75 | + | channel <- jsonData |
| 76 | + | }() |
| 77 | + | |
61 | 78 | | } |
62 | 79 | | |
63 | | - | for i:=0; i<len(ips); i++ { |
| 80 | + | go func() { |
| 81 | + | wg.Wait() |
| 82 | + | close(channel) |
| 83 | + | }() |
| 84 | + | |
| 85 | + | if jsonFile != "" { |
| 86 | + | saveJson(channel, jsonFile) |
| 87 | + | return |
| 88 | + | } |
| 89 | + | |
| 90 | + | for i := 0; i < len(ips); i++ { |
64 | 91 | | printResult(<-channel, noCPEs, noHostnames, noTags, noVulns, noColor) |
65 | 92 | | } |
66 | 93 | | } |
67 | 94 | | |
68 | 95 | | |
69 | | - | func getData(ip string, channel chan Response) { |
| 96 | + | func getData(ip string) Response { |
70 | 97 | | |
71 | 98 | | res, err := http.Get( |
72 | 99 | | fmt.Sprintf("https://internetdb.shodan.io/%s", ip), |
73 | 100 | | ) |
74 | 101 | | |
75 | 102 | | if err != nil { |
76 | | - | return |
| 103 | + | log.Fatalf("Couldn't connect to the server!") |
| 104 | + | return Response{} |
77 | 105 | | } |
78 | 106 | | |
79 | 107 | | raw, err := ioutil.ReadAll(res.Body) |
80 | | - | |
81 | 108 | | if err != nil { |
82 | | - | return |
| 109 | + | log.Fatalf("Couldn't read the data!") |
| 110 | + | return Response{} |
83 | 111 | | } |
84 | 112 | | |
85 | 113 | | res.Body.Close() |
86 | 114 | | |
87 | | - | var wrapper Response |
88 | | - | err = json.Unmarshal(raw, &wrapper) |
| 115 | + | var jsonData Response |
| 116 | + | err = json.Unmarshal(raw, &jsonData) |
89 | 117 | | |
90 | 118 | | if err != nil { |
91 | | - | return |
| 119 | + | log.Fatalf("The data is incorrect!") |
| 120 | + | return Response{} |
92 | 121 | | } |
93 | 122 | | |
94 | | - | channel <- wrapper |
| 123 | + | return jsonData |
95 | 124 | | } |
96 | 125 | | |
97 | | - | func printResult(output Response, noCPEs bool, noHostnames bool, noTags bool, noVulns bool, noColor bool) { |
| 126 | + | |
| 127 | + | func saveJson(chData chan Response, jsonFile string) { |
| 128 | + | |
| 129 | + | var jsonDatas []Response |
| 130 | + | for jsonData := range chData { |
| 131 | + | if jsonData.IP != "" { |
| 132 | + | jsonDatas = append(jsonDatas, jsonData) |
| 133 | + | } |
| 134 | + | } |
| 135 | + | |
| 136 | + | if len(jsonDatas) != 0 { |
| 137 | + | stringData, _ := json.Marshal(jsonDatas) |
| 138 | + | _ = ioutil.WriteFile(jsonFile, stringData, 0644) |
| 139 | + | } |
| 140 | + | } |
| 141 | + | |
| 142 | + | |
| 143 | + | func printResult(jsonData Response, noCPEs bool, noHostnames bool, noTags bool, noVulns bool, noColor bool) { |
98 | 144 | | |
99 | 145 | | builder := &strings.Builder{} |
100 | 146 | | |
101 | | - | fmt.Println(output.IP) |
| 147 | + | if jsonData.IP == "" { |
| 148 | + | return |
| 149 | + | } |
| 150 | + | |
| 151 | + | fmt.Println(jsonData.IP) |
102 | 152 | | |
103 | | - | ports := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(output.Ports)), ", "), "[]") |
| 153 | + | ports := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(jsonData.Ports)), ", "), "[]") |
104 | 154 | | |
105 | 155 | | if !noColor { |
106 | 156 | | builder.WriteString("Ports: " + aurora.Green(ports).String() + "\n") |
| skipped 1 lines |
108 | 158 | | builder.WriteString("Ports: " + ports + "\n") |
109 | 159 | | } |
110 | 160 | | |
111 | | - | if (!noCPEs && len(output.CPES) > 0) { |
112 | | - | cpes := strings.Join(output.CPES, ", ") |
| 161 | + | if (!noCPEs && len(jsonData.CPES) > 0) { |
| 162 | + | cpes := strings.Join(jsonData.CPES, ", ") |
113 | 163 | | if !noColor { |
114 | 164 | | builder.WriteString("CPEs: " + aurora.Yellow(cpes).String() + "\n") |
115 | 165 | | } else { |
| skipped 1 lines |
117 | 167 | | } |
118 | 168 | | } |
119 | 169 | | |
120 | | - | if (!noVulns && len(output.Vulns) > 0) { |
121 | | - | vulns := strings.Join(output.Vulns, ", ") |
| 170 | + | if (!noVulns && len(jsonData.Vulns) > 0) { |
| 171 | + | vulns := strings.Join(jsonData.Vulns, ", ") |
122 | 172 | | if !noColor { |
123 | 173 | | builder.WriteString("Vulnerabilities: " + aurora.Red(vulns).String() + "\n") |
124 | 174 | | } else { |
| skipped 1 lines |
126 | 176 | | } |
127 | 177 | | } |
128 | 178 | | |
129 | | - | if (!noHostnames && len(output.Hostnames) > 0) { |
130 | | - | hostnames := strings.Join(output.Hostnames, ", ") |
| 179 | + | if (!noHostnames && len(jsonData.Hostnames) > 0) { |
| 180 | + | hostnames := strings.Join(jsonData.Hostnames, ", ") |
131 | 181 | | if !noColor { |
132 | 182 | | builder.WriteString("Hostnames: " + aurora.Blue(hostnames).String() + "\n") |
133 | 183 | | } else { |
| skipped 1 lines |
135 | 185 | | } |
136 | 186 | | } |
137 | 187 | | |
138 | | - | if (!noTags && len(output.Tags) > 0) { |
139 | | - | tags := strings.Join(output.Tags, ", ") |
| 188 | + | if (!noTags && len(jsonData.Tags) > 0) { |
| 189 | + | tags := strings.Join(jsonData.Tags, ", ") |
140 | 190 | | if !noColor { |
141 | 191 | | builder.WriteString("Tags: " + aurora.Magenta(tags).String() + "\n") |
142 | 192 | | } else { |
| skipped 6 lines |