|
@@ -22,7 +22,7 @@ const (
|
22
|
22
|
// 'version' of the database schema
|
23
|
23
|
keySchemaVersion = "db.version"
|
24
|
24
|
// latest schema of the db
|
25
|
|
- latestDbSchema = "3"
|
|
25
|
+ latestDbSchema = "4"
|
26
|
26
|
)
|
27
|
27
|
|
28
|
28
|
type SchemaChanger func(*Config, *buntdb.Tx) error
|
|
@@ -278,6 +278,118 @@ func schemaChangeV2ToV3(config *Config, tx *buntdb.Tx) error {
|
278
|
278
|
return nil
|
279
|
279
|
}
|
280
|
280
|
|
|
281
|
+// 1. ban info format changed (from `legacyBanInfo` below to `IPBanInfo`)
|
|
282
|
+// 2. dlines against individual IPs are normalized into dlines against the appropriate /128 network
|
|
283
|
+func schemaChangeV3ToV4(config *Config, tx *buntdb.Tx) error {
|
|
284
|
+ type ipRestrictTime struct {
|
|
285
|
+ Duration time.Duration
|
|
286
|
+ Expires time.Time
|
|
287
|
+ }
|
|
288
|
+ type legacyBanInfo struct {
|
|
289
|
+ Reason string `json:"reason"`
|
|
290
|
+ OperReason string `json:"oper_reason"`
|
|
291
|
+ OperName string `json:"oper_name"`
|
|
292
|
+ Time *ipRestrictTime `json:"time"`
|
|
293
|
+ }
|
|
294
|
+
|
|
295
|
+ now := time.Now()
|
|
296
|
+ legacyToNewInfo := func(old legacyBanInfo) (new_ IPBanInfo) {
|
|
297
|
+ new_.Reason = old.Reason
|
|
298
|
+ new_.OperReason = old.OperReason
|
|
299
|
+ new_.OperName = old.OperName
|
|
300
|
+
|
|
301
|
+ if old.Time == nil {
|
|
302
|
+ new_.TimeCreated = now
|
|
303
|
+ new_.Duration = 0
|
|
304
|
+ } else {
|
|
305
|
+ new_.TimeCreated = old.Time.Expires.Add(-1 * old.Time.Duration)
|
|
306
|
+ new_.Duration = old.Time.Duration
|
|
307
|
+ }
|
|
308
|
+ return
|
|
309
|
+ }
|
|
310
|
+
|
|
311
|
+ var keysToDelete []string
|
|
312
|
+
|
|
313
|
+ prefix := "bans.dline "
|
|
314
|
+ dlines := make(map[string]IPBanInfo)
|
|
315
|
+ tx.AscendGreaterOrEqual("", prefix, func(key, value string) bool {
|
|
316
|
+ if !strings.HasPrefix(key, prefix) {
|
|
317
|
+ return false
|
|
318
|
+ }
|
|
319
|
+ keysToDelete = append(keysToDelete, key)
|
|
320
|
+
|
|
321
|
+ var lbinfo legacyBanInfo
|
|
322
|
+ id := strings.TrimPrefix(key, prefix)
|
|
323
|
+ err := json.Unmarshal([]byte(value), &lbinfo)
|
|
324
|
+ if err != nil {
|
|
325
|
+ log.Printf("error unmarshaling legacy dline: %v\n", err)
|
|
326
|
+ return true
|
|
327
|
+ }
|
|
328
|
+ // legacy keys can be either an IP or a CIDR
|
|
329
|
+ hostNet, err := utils.NormalizedNetFromString(id)
|
|
330
|
+ if err != nil {
|
|
331
|
+ log.Printf("error unmarshaling legacy dline network: %v\n", err)
|
|
332
|
+ return true
|
|
333
|
+ }
|
|
334
|
+ dlines[utils.NetToNormalizedString(hostNet)] = legacyToNewInfo(lbinfo)
|
|
335
|
+
|
|
336
|
+ return true
|
|
337
|
+ })
|
|
338
|
+
|
|
339
|
+ setOptions := func(info IPBanInfo) *buntdb.SetOptions {
|
|
340
|
+ if info.Duration == 0 {
|
|
341
|
+ return nil
|
|
342
|
+ }
|
|
343
|
+ ttl := info.TimeCreated.Add(info.Duration).Sub(now)
|
|
344
|
+ return &buntdb.SetOptions{Expires: true, TTL: ttl}
|
|
345
|
+ }
|
|
346
|
+
|
|
347
|
+ // store the new dlines
|
|
348
|
+ for id, info := range dlines {
|
|
349
|
+ b, err := json.Marshal(info)
|
|
350
|
+ if err != nil {
|
|
351
|
+ log.Printf("error marshaling migrated dline: %v\n", err)
|
|
352
|
+ continue
|
|
353
|
+ }
|
|
354
|
+ tx.Set(fmt.Sprintf("bans.dlinev2 %s", id), string(b), setOptions(info))
|
|
355
|
+ }
|
|
356
|
+
|
|
357
|
+ // same operations against klines
|
|
358
|
+ prefix = "bans.kline "
|
|
359
|
+ klines := make(map[string]IPBanInfo)
|
|
360
|
+ tx.AscendGreaterOrEqual("", prefix, func(key, value string) bool {
|
|
361
|
+ if !strings.HasPrefix(key, prefix) {
|
|
362
|
+ return false
|
|
363
|
+ }
|
|
364
|
+ keysToDelete = append(keysToDelete, key)
|
|
365
|
+ mask := strings.TrimPrefix(key, prefix)
|
|
366
|
+ var lbinfo legacyBanInfo
|
|
367
|
+ err := json.Unmarshal([]byte(value), &lbinfo)
|
|
368
|
+ if err != nil {
|
|
369
|
+ log.Printf("error unmarshaling legacy kline: %v\n", err)
|
|
370
|
+ return true
|
|
371
|
+ }
|
|
372
|
+ klines[mask] = legacyToNewInfo(lbinfo)
|
|
373
|
+ return true
|
|
374
|
+ })
|
|
375
|
+
|
|
376
|
+ for mask, info := range klines {
|
|
377
|
+ b, err := json.Marshal(info)
|
|
378
|
+ if err != nil {
|
|
379
|
+ log.Printf("error marshaling migrated kline: %v\n", err)
|
|
380
|
+ continue
|
|
381
|
+ }
|
|
382
|
+ tx.Set(fmt.Sprintf("bans.klinev2 %s", mask), string(b), setOptions(info))
|
|
383
|
+ }
|
|
384
|
+
|
|
385
|
+ // clean up all the old entries
|
|
386
|
+ for _, key := range keysToDelete {
|
|
387
|
+ tx.Delete(key)
|
|
388
|
+ }
|
|
389
|
+
|
|
390
|
+ return nil
|
|
391
|
+}
|
|
392
|
+
|
281
|
393
|
func init() {
|
282
|
394
|
allChanges := []SchemaChange{
|
283
|
395
|
{
|
|
@@ -290,6 +402,11 @@ func init() {
|
290
|
402
|
TargetVersion: "3",
|
291
|
403
|
Changer: schemaChangeV2ToV3,
|
292
|
404
|
},
|
|
405
|
+ {
|
|
406
|
+ InitialVersion: "3",
|
|
407
|
+ TargetVersion: "4",
|
|
408
|
+ Changer: schemaChangeV3ToV4,
|
|
409
|
+ },
|
293
|
410
|
}
|
294
|
411
|
|
295
|
412
|
// build the index
|