blob: 571247105049ed38c34ec1612b70b4ddbe66622c [file] [log] [blame]
Serge Bazanskiec71cb52019-08-22 18:13:13 +02001package main
2
3import (
4 "context"
5 "encoding/hex"
6 "fmt"
7 "io"
8
9 pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
10 "code.hackerspace.pl/hscloud/bgpwtf/cccampix/verifier/model"
11 "github.com/golang/glog"
12 "google.golang.org/grpc/codes"
13 "google.golang.org/grpc/status"
14)
15
16func (s *service) ProcessorStatus(ctx context.Context, req *pb.ProcessorStatusRequest) (*pb.ProcessorStatusResponse, error) {
17 s.processorsMu.RLock()
18 defer s.processorsMu.RUnlock()
19
20 res := &pb.ProcessorStatusResponse{
21 Processors: make([]*pb.ProcessorStatusResponse_Processor, len(s.processors)),
22 }
23
24 i := 0
25 for _, p := range s.processors {
26 res.Processors[i] = &pb.ProcessorStatusResponse_Processor{
27 Name: p.name,
28 Status: pb.ProcessorStatusResponse_Processor_STATUS_OK,
29 LastRun: 0,
30 NextRun: 0,
31 }
32
33 if p.lastRun != nil {
34 res.Processors[i].LastRun = p.lastRun.UnixNano()
35 res.Processors[i].NextRun = p.p.NextRun(*p.lastRun, p.lastErr != nil).UnixNano()
36 }
37
38 if p.lastErr != nil {
39 res.Processors[i].Status = pb.ProcessorStatusResponse_Processor_STATUS_ERROR
40 }
41
42 i += 1
43 }
44 return res, nil
45}
46
47func (s *service) PeerSummary(req *pb.PeerSummaryRequest, stream pb.Verifier_PeerSummaryServer) error {
48 peers, err := s.model.GetCheckablePeers(stream.Context())
49 if err != nil {
50 glog.Errorf("model.GetCheckablePeers: %v", err)
51 return status.Error(codes.Unavailable, "model error")
52 }
53
54 asns := make([]int64, len(peers))
55 asnToRes := make(map[int64]*pb.PeerSummaryResponse)
56
57 for i, peer := range peers {
58 routers := make([]*pb.PeeringDBMember_Router, len(peer.Routers))
59 for i, router := range peer.Routers {
60 routers[i] = &pb.PeeringDBMember_Router{}
61 if router.V4 != nil {
62 routers[i].Ipv4 = router.V4.String()
63 }
64 if router.V6 != nil {
65 routers[i].Ipv6 = router.V6.String()
66 }
67 }
68 p := &pb.PeeringDBMember{
69 Asn: peer.ASN,
70 Name: peer.Name,
71 Routers: routers,
72 }
73 res := &pb.PeerSummaryResponse{
74 PeeringdbInfo: p,
75 CheckStatus: pb.PeerSummaryResponse_STATUS_OK,
76 }
77 asnToRes[peer.ASN] = res
78 asns[i] = peer.ASN
79 }
80
81 checkres, err := s.model.GetPeerCheckResults(stream.Context(), asns)
82 if err != nil {
83 glog.Errorf("GetPeerCheckResults(%v): %v", asns, err)
84 for _, res := range asnToRes {
85 res.CheckStatus = pb.PeerSummaryResponse_STATUS_UNKNOWN
86 }
87 } else {
88 passedChecks := make(map[int64]map[string]bool)
89 for _, c := range checkres {
90 if _, ok := passedChecks[c.PeerASN]; !ok {
91 passedChecks[c.PeerASN] = make(map[string]bool)
92 }
93 passedChecks[c.PeerASN][c.CheckName] = c.Status == model.PeerCheckStatus_Okay
94 }
95
96 for asn, checks := range passedChecks {
97 for _, required := range s.requiredChecks {
98 if !checks[required] {
99 asnToRes[asn].CheckStatus = pb.PeerSummaryResponse_STATUS_FAILED
100 break
101 }
102 }
103 }
104 }
105
106 for _, res := range asnToRes {
107 if err := stream.Send(res); err != nil {
108 return err
109 }
110 }
111
112 return nil
113}
114
115func (s *service) PeerDetails(ctx context.Context, req *pb.PeerDetailsRequest) (*pb.PeerDetailsResponse, error) {
116 if req.Asn <= 0 {
117 return nil, status.Error(codes.InvalidArgument, "asn must be set")
118 }
119
120 res := &pb.PeerDetailsResponse{}
121
122 peeringdb, err := s.model.GetPeeringDBPeer(ctx, req.Asn)
123 if err != nil {
124 glog.Errorf("GetPeeringDBPeer(%v): %v", req.Asn, err)
125 return nil, status.Error(codes.Unavailable, "could not get allowed prefixes")
126 }
127
128 if peeringdb.Asn != req.Asn {
129 return nil, status.Error(codes.NotFound, "no such ASN")
130 }
131
132 res.PeeringdbInfo = peeringdb
133
134 checkres, err := s.model.GetPeerCheckResults(ctx, []int64{req.Asn})
135 if err != nil {
136 glog.Errorf("GetPeerCheckResults(%v): %v", req.Asn, err)
137 return nil, status.Error(codes.Unavailable, "could not get check results")
138 }
139
140 res.Checks = make([]*pb.PeerDetailsResponse_Check, len(checkres))
141 for i, check := range checkres {
142 status := pb.PeerDetailsResponse_Check_STATUS_INVALID
143 switch check.Status {
144 case model.PeerCheckStatus_Okay:
145 status = pb.PeerDetailsResponse_Check_STATUS_OK
146 case model.PeerCheckStatus_SoftFailed:
147 status = pb.PeerDetailsResponse_Check_STATUS_OK
148 case model.PeerCheckStatus_Failed:
149 status = pb.PeerDetailsResponse_Check_STATUS_FAILED
150 }
151 res.Checks[i] = &pb.PeerDetailsResponse_Check{
152 Name: check.CheckName,
153 Status: status,
154 Time: check.Time.UnixNano(),
155 Msg: check.Message,
156 }
157 }
158
159 prefixes, err := s.model.GetAllowedPrefixes(ctx, req.Asn)
160 if err != nil {
161 glog.Errorf("GetAllowedPrefixes(%v): %v", req.Asn, err)
162 return nil, status.Error(codes.Unavailable, "could not get allowed prefixes")
163 }
164
165 res.AllowedPrefixes = make([]*pb.PeerDetailsResponse_AllowedPrefix, len(prefixes))
166 for i, prefix := range prefixes {
167 res.AllowedPrefixes[i] = &pb.PeerDetailsResponse_AllowedPrefix{
168 Prefix: prefix.Prefix.String(),
169 MaxLength: prefix.MaxLength,
170 Ta: prefix.TA,
171 }
172 }
173
174 return res, nil
175}
176
177func (s *service) RouterHeartbeat(ctx context.Context, req *pb.RouterHeartbeatRequest) (*pb.RouterHeartbeatResponse, error) {
178 if req.Name == "" {
179 return nil, status.Error(codes.InvalidArgument, "name must be set")
180 }
181
182 pcfgM := make(map[string]*model.PeerConfiguration)
183 pcfgs, err := s.model.GetPeerConfiguration(ctx)
184 if err != nil {
185 glog.Errorf("GetPeerConfiguration: %v", err)
186 return nil, status.Error(codes.Unavailable, "could not get peer configs")
187 }
188
189 for _, pcfg := range pcfgs {
190 ask := fmt.Sprintf("AS%d", pcfg.Peer.ASN)
191 pcfgM[ask] = pcfg
192 }
193
194 peers, err := s.model.GetCheckablePeers(ctx)
195 if err != nil {
196 glog.Errorf("GetChecablePeers: %v", err)
197 return nil, status.Error(codes.Unavailable, "could not get peers")
198 }
199
200 asconfs := make(map[string]*pb.RouterHeartbeatResponse_ASConfig)
201
202 for _, peer := range peers {
203 as := fmt.Sprintf("AS%d", peer.ASN)
204
205 pcfg, ok := pcfgM[as]
206 if !ok {
207 continue
208 }
209
210 asconfs[as] = &pb.RouterHeartbeatResponse_ASConfig{
211 Asn: peer.ASN,
212 Routers: make([]*pb.RouterHeartbeatResponse_ASConfig_Router, len(pcfg.Peer.Routers)),
213 Prefixes: []*pb.RouterHeartbeatResponse_ASConfig_AllowedPrefix{},
214 }
215
216 glog.Infof("%+v", pcfg.Peer.Routers)
217 for i, r := range pcfg.Peer.Routers {
218 ipv6 := ""
219 if r.V6 != nil {
220 ipv6 = r.V6.String()
221 }
222 ipv4 := ""
223 if r.V4 != nil {
224 ipv4 = r.V4.String()
225 }
226 asconfs[as].Routers[i] = &pb.RouterHeartbeatResponse_ASConfig_Router{
227 Ipv6: ipv6,
228 Ipv4: ipv4,
229 Password: r.Config.BGPSecret,
230 }
231 }
232
233 prefixes, err := s.model.GetAllowedPrefixes(ctx, peer.ASN)
234 if err != nil {
235 glog.Errorf("GetAllowedPrefixes(_, %d): %v", peer.ASN, err)
236 return nil, status.Error(codes.Unavailable, "could not get peer prefixes")
237 }
238
239 for _, prefix := range prefixes {
240 asconfs[as].Prefixes = append(asconfs[as].Prefixes, &pb.RouterHeartbeatResponse_ASConfig_AllowedPrefix{
241 Prefix: prefix.Prefix.String(),
242 MaxLength: prefix.MaxLength,
243 })
244 }
245 }
246
247 res := &pb.RouterHeartbeatResponse{
248 AsConfigs: make([]*pb.RouterHeartbeatResponse_ASConfig, len(asconfs)),
249 }
250
251 i := 0
252 for _, asconf := range asconfs {
253 res.AsConfigs[i] = asconf
254 i += 1
255 }
256
257 return res, nil
258}
259
260func (s *service) PeerSecrets(ctx context.Context, req *pb.PeerSecretsRequest) (*pb.PeerSecretsResponse, error) {
261 if req.Asn <= 0 {
262 return nil, status.Error(codes.InvalidArgument, "asn must be set")
263 }
264 pcrs, err := s.model.GetPeerConfiguration(ctx)
265 if err != nil {
266 glog.Errorf("GetPeerConfiguration: %v", err)
267 return nil, status.Error(codes.Unavailable, "error when retrieving peer configs")
268 }
269
270 var pcr *model.PeerConfiguration
271 for _, p := range pcrs {
272 if p.Peer.ASN == req.Asn {
273 pcr = p
274 break
275 }
276 }
277
278 if pcr == nil {
279 return nil, status.Error(codes.NotFound, "no such ASN")
280 }
281
282 plain := fmt.Sprintf(`
283Hello AS %d!
284
285Here are your config settings:
286`, req.Asn)
287
288 for _, router := range pcr.Peer.Routers {
289 if router.V4 != nil {
290 plain += fmt.Sprintf(`
Serge Bazanskief937472019-08-29 14:53:18 +0200291our addresses: 185.236.243.5 (rs1), 185.236.243.6 (rs2), 185.236.243.7 (upstream)
Serge Bazanskiec71cb52019-08-22 18:13:13 +0200292 our asn: 208521
293 your address: %s
294 your asn: %d
295 bgp secret: %s
296`, router.V4.String(), req.Asn, router.Config.BGPSecret)
297 }
298 if router.V6 != nil {
299 plain += fmt.Sprintf(`
Serge Bazanskief937472019-08-29 14:53:18 +0200300our addresses: 2a0d:eb02:4242:4242::5 (rs1), 2a0d:eb02:4242:4242::6 (rs2), 2a0d:eb02:4242:4242::7 (upstream)
Serge Bazanskiec71cb52019-08-22 18:13:13 +0200301 our asn: 208521
302 your address: %s
303 your asn: %d
304 bgp secret: %s
305`, router.V6.String(), req.Asn, router.Config.BGPSecret)
306 }
307 }
308
309 plain += `
310Happy exchanging!
311bgp.wtf (DECT: 4735)
312`
313
314 key, err := s.model.GetPeerPGPKey(ctx, req.Asn)
315 if err != nil {
316 glog.Errorf("GetPeerPGPKey: %v", err)
317 return nil, status.Error(codes.Unavailable, "could not get pgp key")
318 }
319
320 plainB := []byte(plain)
321
322 stream, err := s.pgp.Encrypt(ctx)
323 if err != nil {
324 glog.Errorf("Encrypt: %v", err)
325 return nil, status.Error(codes.Unavailable, "could not encrypt")
326 }
327
328 fingerprint, err := hex.DecodeString(key.Fingerprint)
329 if err != nil {
330 glog.Errorf("Invalid fingerprint %q: %v", key.Fingerprint, err)
331 return nil, status.Error(codes.Unavailable, "could not encrypt")
332 }
333
334 reqE := &pb.EncryptRequest{
335 Data: plainB,
336 Info: pb.EncryptRequest_CHUNK_LAST,
337 Fingerprint: fingerprint,
338 }
339
340 if err := stream.Send(reqE); err != nil {
341 glog.Errorf("Encrypt.Send: %v", err)
342 return nil, status.Error(codes.Unavailable, "could not encrypt")
343 }
344 stream.CloseSend()
345
346 cipher := []byte{}
347 for {
348 in, err := stream.Recv()
349 if err == io.EOF {
350 break
351 }
352 if err != nil {
353 glog.Errorf("Encrypt.Recv: %v", err)
354 return nil, status.Error(codes.Unavailable, "could not encrypt")
355 }
356 cipher = append(cipher, in.Data...)
357 }
358
359 return &pb.PeerSecretsResponse{
360 PgpData: cipher,
361 }, nil
362}