Browse code

New RPC commands which manipulate the content of the DNS cache:

- dns.view: dumps the cache
- dns.delete_all: deletes all the entries
- dns.add_a: adds an A record
- dns.add_aaaa: adds an AAAA record
- dns.add_srv: adds an SRV record
- dns.delete_a: deletes an A record
- dns.delete_aaaa: deletes an AAAA record
- dns.delete_srv: deletes an SRV record

Miklos Tirpak authored on 26/07/2007 11:32:01
Showing 3 changed files
... ...
@@ -43,6 +43,15 @@
43 43
 void dns_cache_debug(rpc_t* rpc, void* ctx);
44 44
 void dns_cache_debug_all(rpc_t* rpc, void* ctx);
45 45
 void dns_cache_mem_info(rpc_t* rpc, void* ctx);
46
+void dns_cache_view(rpc_t* rpc, void* ctx);
47
+void dns_cache_delete_all(rpc_t* rpc, void* ctx);
48
+void dns_cache_add_a(rpc_t* rpc, void* ctx);
49
+void dns_cache_add_aaaa(rpc_t* rpc, void* ctx);
50
+void dns_cache_add_srv(rpc_t* rpc, void* ctx);
51
+void dns_cache_delete_a(rpc_t* rpc, void* ctx);
52
+void dns_cache_delete_aaaa(rpc_t* rpc, void* ctx);
53
+void dns_cache_delete_srv(rpc_t* rpc, void* ctx);
54
+
46 55
 
47 56
 static const char* dns_cache_mem_info_doc[] = {
48 57
 	"dns cache memory info.",    /* Documentation string */
... ...
@@ -58,6 +67,45 @@ static const char* dns_cache_debug_all_doc[] = {
58 67
 	0                              /* Method signature(s) */
59 68
 };
60 69
 
70
+static const char* dns_cache_view_doc[] = {
71
+	"dns cache dump in a human-readable format",
72
+	0
73
+};
74
+
75
+static const char* dns_cache_delete_all_doc[] = {
76
+	"deletes all the entries from the DNS cache",
77
+	0
78
+};
79
+
80
+static const char* dns_cache_add_a_doc[] = {
81
+	"adds an A record to the DNS cache",
82
+	0
83
+};
84
+
85
+static const char* dns_cache_add_aaaa_doc[] = {
86
+	"adds an AAAA record to the DNS cache",
87
+	0
88
+};
89
+static const char* dns_cache_add_srv_doc[] = {
90
+	"adds an SRV record to the DNS cache",
91
+	0
92
+};
93
+
94
+static const char* dns_cache_delete_a_doc[] = {
95
+	"deletes an A record from the DNS cache",
96
+	0
97
+};
98
+
99
+static const char* dns_cache_delete_aaaa_doc[] = {
100
+	"deletes an AAAA record from the DNS cache",
101
+	0
102
+};
103
+
104
+static const char* dns_cache_delete_srv_doc[] = {
105
+	"deletes an SRV record from the DNS cache",
106
+	0
107
+};
108
+
61 109
 #ifdef DNS_WATCHDOG_SUPPORT
62 110
 void dns_set_server_state_rpc(rpc_t* rpc, void* ctx);
63 111
 
... ...
@@ -479,6 +527,14 @@ rpc_export_t core_rpc_methods[] = {
479 527
 	{"dns.mem_info",          dns_cache_mem_info,     dns_cache_mem_info_doc,     0	},
480 528
 	{"dns.debug",          dns_cache_debug,           dns_cache_debug_doc,        0	},
481 529
 	{"dns.debug_all",      dns_cache_debug_all,       dns_cache_debug_all_doc,        0	},
530
+	{"dns.view",               dns_cache_view,        dns_cache_view_doc,        0	},
531
+	{"dns.delete_all",         dns_cache_delete_all,  dns_cache_delete_all_doc,  0	},
532
+	{"dns.add_a",              dns_cache_add_a,       dns_cache_add_a_doc,       0	},
533
+	{"dns.add_aaaa",           dns_cache_add_aaaa,    dns_cache_add_aaaa_doc,    0	},
534
+	{"dns.add_srv",            dns_cache_add_srv,     dns_cache_add_srv_doc,     0	},
535
+	{"dns.delete_a",           dns_cache_delete_a,    dns_cache_delete_a_doc,    0	},
536
+	{"dns.delete_aaaa",        dns_cache_delete_aaaa, dns_cache_delete_aaaa_doc, 0	},
537
+	{"dns.delete_srv",         dns_cache_delete_srv,  dns_cache_delete_srv_doc,  0	},
482 538
 #ifdef DNS_WATCHDOG_SUPPORT
483 539
 	{"dns.set_server_state",   dns_set_server_state_rpc, dns_set_server_state_doc, 0 },
484 540
 #endif
... ...
@@ -35,6 +35,8 @@
35 35
  *  2007-06-16  naptr support (andrei)
36 36
  *  2008-07-18  DNS watchdog support -- can be used to inform the core
37 37
  *              that the DNS servers are down (Miklos)
38
+ *  2008-07-25  various rpc commands to manipulate the content
39
+ *		of the cache (Miklos)
38 40
  */
39 41
 
40 42
 #ifdef USE_DNS_CACHE
... ...
@@ -824,6 +826,61 @@ inline static struct dns_hash_entry* dns_cache_mk_ip_entry(str* name,
824 826
 	return e;
825 827
 }
826 828
 
829
+/* creates an srv hash entry from the given parameters
830
+ * returns 0 on error */
831
+static struct dns_hash_entry* dns_cache_mk_srv_entry(str* name,
832
+							unsigned short priority,
833
+							unsigned short weight,
834
+							unsigned short port,
835
+							str* rr_name,
836
+							int ttl)
837
+{
838
+	struct dns_hash_entry* e;
839
+	int size;
840
+	ticks_t now;
841
+	
842
+	/* everything is allocated in one block: dns_hash_entry + name +
843
+	 * + dns_rr + rdata;  dns_rr must start at an aligned adress,
844
+	 * hence we need to round dns_hash_entry+name size to a sizeof(long),
845
+	 * and similarly, dns_rr must be rounded to sizeof(short).
846
+	 * multiple.
847
+	 * Memory image:
848
+	 * struct dns_hash_entry
849
+	 * name (name_len+1 bytes)
850
+	 * padding to multiple of sizeof(long)
851
+	 * dns_rr
852
+	 * padding to multiple of sizeof(short)
853
+	 * rdata 
854
+	  */
855
+	size=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1) + 
856
+		ROUND_SHORT(sizeof(struct dns_rr)) +
857
+		sizeof(struct srv_rdata)-1 +
858
+		rr_name->len+1;
859
+
860
+	e=shm_malloc(size);
861
+	if (e==0){
862
+		LOG(L_ERR, "ERROR: dns_cache_srv_ip_entry: out of memory\n");
863
+		return 0;
864
+	}
865
+	memset(e, 0, size); /* init with 0*/
866
+	e->total_size=size;
867
+	e->name_len=name->len;
868
+	e->type=T_SRV;
869
+	now=get_ticks_raw();
870
+	e->last_used=now;
871
+	e->expire=now+S_TO_TICKS(ttl);
872
+	memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
873
+	e->rr_lst=(void*)((char*)e+
874
+				ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
875
+	e->rr_lst->rdata=(void*)((char*)e->rr_lst+ROUND_SHORT(sizeof(struct dns_rr)));
876
+	e->rr_lst->expire=e->expire;
877
+	((struct srv_rdata*)e->rr_lst->rdata)->priority = priority;
878
+	((struct srv_rdata*)e->rr_lst->rdata)->weight = weight;
879
+	((struct srv_rdata*)e->rr_lst->rdata)->port = port;
880
+	((struct srv_rdata*)e->rr_lst->rdata)->name_len = rr_name->len;
881
+	memcpy(((struct srv_rdata*)e->rr_lst->rdata)->name, rr_name->s, rr_name->len);
882
+	return e;
883
+}
827 884
 
828 885
 
829 886
 /* create a dns hash entry from a name and a rdata list (pkg_malloc'ed)
... ...
@@ -3098,6 +3155,505 @@ void dns_cache_debug_all(rpc_t* rpc, void* ctx)
3098 3155
 	UNLOCK_DNS_HASH();
3099 3156
 }
3100 3157
 
3158
+static char *print_type(unsigned short type)
3159
+{
3160
+	switch (type) {
3161
+		case T_A:
3162
+			return "A";
3163
+		case T_AAAA:
3164
+			return "AAAA";
3165
+		case T_SRV:
3166
+			return "SRV";
3167
+		case T_NAPTR:
3168
+			return "NAPTR";
3169
+		case T_CNAME:
3170
+			return "CNAME";
3171
+		default:
3172
+			return "unkown";
3173
+	}
3174
+}
3175
+
3176
+/* dumps the content of the cache in a human-readable format */
3177
+void dns_cache_view(rpc_t* rpc, void* ctx)
3178
+{
3179
+	int h;
3180
+	struct dns_hash_entry* e;
3181
+	struct dns_rr* rr;
3182
+	struct ip_addr ip;
3183
+	ticks_t now;
3184
+	void* handle;
3185
+	str s;
3186
+	
3187
+	now=get_ticks_raw();
3188
+	LOCK_DNS_HASH();
3189
+		for (h=0; h<DNS_HASH_SIZE; h++){
3190
+			clist_foreach(&dns_hash[h], e, next){
3191
+				rpc->add(ctx, "{", &handle);
3192
+				rpc->struct_add(handle, "s", "name", e->name);
3193
+				rpc->struct_add(handle, "s", "type", print_type(e->type));
3194
+				rpc->struct_add(handle, "d", "size (bytes)", e->total_size);
3195
+				rpc->struct_add(handle, "d", "reference counter", e->refcnt.val);
3196
+				rpc->struct_add(handle, "d", "expires in (s)", (s_ticks_t)(e->expire-now)<0?-1:
3197
+									TICKS_TO_S(e->expire-now));
3198
+				rpc->struct_add(handle, "d", "last used (s)", TICKS_TO_S(now-e->last_used));
3199
+				rpc->struct_add(handle, "d", "error flags", e->err_flags);
3200
+
3201
+				for (rr=e->rr_lst; rr; rr=rr->next){
3202
+					switch(e->type){
3203
+						case T_A:
3204
+						case T_AAAA:
3205
+							if (dns_rr2ip(e->type, rr, &ip)==0){
3206
+								rpc->struct_add(handle, "s", "rr ip",
3207
+									ip_addr2a(&ip) );
3208
+							}else{
3209
+								rpc->struct_add(handle, "s", "rr ip",
3210
+									"<error: bad rr>");
3211
+							}
3212
+							break;
3213
+						case T_SRV:
3214
+							rpc->struct_add(handle, "s", "rr name",
3215
+									((struct srv_rdata*)(rr->rdata))->name);
3216
+							rpc->struct_add(handle, "d", "rr port",
3217
+									((struct srv_rdata*)(rr->rdata))->port);
3218
+							rpc->struct_add(handle, "d", "rr priority",
3219
+									((struct srv_rdata*)(rr->rdata))->priority);
3220
+							rpc->struct_add(handle, "d", "rr weight",
3221
+									((struct srv_rdata*)(rr->rdata))->weight);
3222
+							break;
3223
+						case T_NAPTR:
3224
+							rpc->struct_add(handle, "d", "rr order",
3225
+									((struct naptr_rdata*)(rr->rdata))->order);
3226
+							rpc->struct_add(handle, "d", "rr preference",
3227
+									((struct naptr_rdata*)(rr->rdata))->pref);
3228
+
3229
+							s.s = ((struct naptr_rdata*)(rr->rdata))->flags;
3230
+							s.len = ((struct naptr_rdata*)(rr->rdata))->flags_len;
3231
+							rpc->struct_add(handle, "S", "rr flags", &s);
3232
+
3233
+							s.s = ((struct naptr_rdata*)(rr->rdata))->services;
3234
+							s.len = ((struct naptr_rdata*)(rr->rdata))->services_len;
3235
+							rpc->struct_add(handle, "S", "rr service", &s);
3236
+
3237
+							s.s = ((struct naptr_rdata*)(rr->rdata))->regexp;
3238
+							s.len = ((struct naptr_rdata*)(rr->rdata))->regexp_len;
3239
+							rpc->struct_add(handle, "S", "rr regexp", &s);
3240
+
3241
+							s.s = ((struct naptr_rdata*)(rr->rdata))->repl;
3242
+							s.len = ((struct naptr_rdata*)(rr->rdata))->repl_len;
3243
+							rpc->struct_add(handle, "S", "rr replacement", &s);
3244
+							break;
3245
+						case T_CNAME:
3246
+							rpc->struct_add(handle, "s",  "rr name",
3247
+									((struct cname_rdata*)(rr->rdata))->name);
3248
+							break;
3249
+						default:
3250
+							rpc->struct_add(ctx, "ss", "resource record",
3251
+									"unknown");
3252
+					}
3253
+					rpc->struct_add(handle, "d", "rr expires in (s)", (s_ticks_t)(rr->expire-now)<0?-1:
3254
+										TICKS_TO_S(rr->expire-now));
3255
+					rpc->struct_add(handle, "d", "rr error flags", rr->err_flags);
3256
+				}
3257
+			}
3258
+		}
3259
+	UNLOCK_DNS_HASH();
3260
+}
3261
+
3262
+
3263
+/* deletes all the entries from the cache */
3264
+void dns_cache_flush(void)
3265
+{
3266
+	int h;
3267
+	struct dns_hash_entry* e;
3268
+	struct dns_hash_entry* tmp;
3269
+
3270
+	DBG("dns_cache_flush(): removing elements from the cache\n");
3271
+	LOCK_DNS_HASH();
3272
+		for (h=0; h<DNS_HASH_SIZE; h++){
3273
+			clist_foreach_safe(&dns_hash[h], e, tmp, next){
3274
+				_dns_hash_remove(e);
3275
+			}
3276
+		}
3277
+	UNLOCK_DNS_HASH();
3278
+}
3279
+
3280
+/* deletes all the entries from the cache */
3281
+void dns_cache_delete_all(rpc_t* rpc, void* ctx)
3282
+{
3283
+	dns_cache_flush();
3284
+}
3285
+
3286
+/* clons an entry and extends the memory area of it for a new rr if rdata_size>0
3287
+ * the new dns_rr struct is initialized, but the rdata is only filled with 0.
3288
+ */
3289
+static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e, int rdata_size, int ttl,
3290
+							struct dns_rr **_new_rr)
3291
+{
3292
+	struct dns_hash_entry *new;
3293
+	struct dns_rr *rr, *last_rr, *new_rr;
3294
+	int size, rounded_size, rr_size;
3295
+	ticks_t now;
3296
+
3297
+	now=get_ticks_raw();
3298
+	size = e->total_size;
3299
+	if (rdata_size) {
3300
+		/* we have to extend the entry */
3301
+		rounded_size = 	ROUND_POINTER(size); /* size may not have been rounded previously */
3302
+		switch (e->type) {
3303
+			case T_A:
3304
+			case T_AAAA:
3305
+			case T_CNAME:
3306
+				rr_size = sizeof(struct dns_rr);
3307
+				break;
3308
+			case T_SRV:
3309
+				rr_size = ROUND_SHORT(sizeof(struct dns_rr));
3310
+				break;
3311
+			case T_NAPTR:
3312
+				rr_size = ROUND_POINTER(sizeof(struct dns_rr));
3313
+				break;
3314
+			default:
3315
+				LOG(L_ERR, "ERROR: dns_cache_clone_entry: type %d not supported\n",
3316
+						e->type);
3317
+				return NULL;				
3318
+		}
3319
+	} else {
3320
+		rounded_size = size; /* no need to round the size, we just clone the entry
3321
+					without extending it */
3322
+		rr_size = 0;
3323
+	}
3324
+
3325
+	new=shm_malloc(rounded_size+rr_size+rdata_size);
3326
+	if (!new) {
3327
+		LOG(L_ERR, "ERROR: dns_cache_clone_entry: out of memory\n");
3328
+		return NULL;
3329
+	}
3330
+	/* clone the entry */
3331
+	memcpy(new, e, size);
3332
+	/* fix the values and pointers */
3333
+	new->next = new->prev = NULL;
3334
+#ifdef DNS_LU_LST
3335
+	new->last_used_lst.next = new->last_used_lst.next = NULL;
3336
+#endif
3337
+	new->rr_lst = (struct dns_rr*)translate_pointer((char*)new, (char*)e, (char*)new->rr_lst);
3338
+	atomic_set(&new->refcnt, 0);
3339
+	new->last_used = now;
3340
+	/* expire and total_size are fixed later if needed */
3341
+	/* fix the pointers inside the rr structures */
3342
+	last_rr = NULL;
3343
+	for (rr=new->rr_lst; rr; rr=rr->next) {
3344
+		rr->rdata = (void*)translate_pointer((char*)new, (char*)e, (char*)rr->rdata);
3345
+		if (rr->next)
3346
+			rr->next = (struct dns_rr*)translate_pointer((char*)new, (char*)e, (char*)rr->next);
3347
+		else
3348
+			last_rr = rr;
3349
+
3350
+		if (e->type == T_NAPTR) {
3351
+			/* there are pointers inside the NAPTR rdata stucture */
3352
+			((struct naptr_rdata*)rr->rdata)->flags =
3353
+				translate_pointer((char*)new, (char*)e,
3354
+					((struct naptr_rdata*)rr->rdata)->flags);
3355
+
3356
+			((struct naptr_rdata*)rr->rdata)->services =
3357
+				translate_pointer((char*)new, (char*)e,
3358
+					((struct naptr_rdata*)rr->rdata)->services);
3359
+
3360
+			((struct naptr_rdata*)rr->rdata)->regexp =
3361
+				translate_pointer((char*)new, (char*)e,
3362
+					((struct naptr_rdata*)rr->rdata)->regexp);
3363
+
3364
+			((struct naptr_rdata*)rr->rdata)->repl =
3365
+				translate_pointer((char*)new, (char*)e,
3366
+					((struct naptr_rdata*)rr->rdata)->repl);
3367
+		}
3368
+	}
3369
+	
3370
+
3371
+	if (rdata_size) {
3372
+		memset(new+size, 0, rounded_size-size+rr_size+rdata_size);
3373
+
3374
+		/* set the pointer to the new rr structure */
3375
+		new_rr = (void*)((char*)new + rounded_size);
3376
+		new_rr->rdata = (void*)((char*)new_rr+rr_size);
3377
+		new_rr->expire = now + S_TO_TICKS(ttl);
3378
+		/* link the rr to the previous one */
3379
+		last_rr->next = new_rr;
3380
+
3381
+		/* fix the total_size and expires values */
3382
+		new->total_size=rounded_size+rr_size+rdata_size;
3383
+		new->expire = MAX(new->expire, new_rr->expire);
3384
+
3385
+
3386
+		if (_new_rr)
3387
+			*_new_rr = new_rr;
3388
+	} else {
3389
+		if (_new_rr)
3390
+			*_new_rr = NULL;
3391
+	}
3392
+
3393
+	return new;
3394
+}
3395
+
3396
+/* Adds a new record to the cache.
3397
+ * If there is an existing record with the same name and value
3398
+ * (ip address in case of A/AAAA record, name in case of SRV record)
3399
+ * only the remaining fields are updated.
3400
+ *
3401
+ * Currently only A, AAAA, and SRV records are supported.
3402
+ */
3403
+static void dns_cache_add_record(rpc_t* rpc, void* ctx, unsigned short type)
3404
+{
3405
+	struct dns_hash_entry *old=NULL, *new=NULL;
3406
+	struct dns_rr *rr;
3407
+	str name;
3408
+	int ttl;
3409
+	str ip, rr_name;
3410
+	int flags;
3411
+	struct ip_addr *ip_addr;
3412
+	int priority, weight, port; 
3413
+	ticks_t expire;
3414
+	int err, h;
3415
+	int size;
3416
+
3417
+	/* eliminate gcc warnings */
3418
+	ip_addr = 0;
3419
+	size = 0;
3420
+
3421
+	switch(type) {
3422
+	case T_A:
3423
+	case T_AAAA:
3424
+		if (rpc->scan(ctx, "SdSd", &name, &ttl, &ip, &flags) < 4)
3425
+			return;
3426
+		break;
3427
+	case T_SRV:
3428
+		if (rpc->scan(ctx, "SddddSd", &name, &ttl, &priority, &weight, &port, &rr_name, &flags) < 7)
3429
+			return;
3430
+		break;
3431
+	case T_CNAME:
3432
+	case T_NAPTR:
3433
+		rpc->fault(ctx, 400, "not implemented");
3434
+		return;			
3435
+	default:
3436
+		rpc->fault(ctx, 400, "unknown type");
3437
+		return;			
3438
+	}
3439
+
3440
+	if (!flags) {
3441
+		/* fix-up the values */
3442
+		switch(type) {
3443
+		case T_A:
3444
+			ip_addr = str2ip(&ip);
3445
+			if (!ip_addr) {
3446
+				rpc->fault(ctx, 400, "Malformed ip address");
3447
+				goto error;
3448
+			}
3449
+			break;
3450
+		case T_AAAA:
3451
+			ip_addr = str2ip6(&ip);
3452
+			if (!ip_addr) {
3453
+				rpc->fault(ctx, 400, "Malformed ip address");
3454
+				goto error;
3455
+			}
3456
+			break;
3457
+		/* case T_SRV: nothing to do */
3458
+		}
3459
+	}
3460
+
3461
+	/* check whether there is a matching entry in the cache */
3462
+	old = dns_hash_get(&name, type, &h, &err);
3463
+	if (old && old->type!=type) {
3464
+		/* probably we found a CNAME instead of the specified type,
3465
+		it is not needed */
3466
+		dns_hash_put(old);
3467
+		old=NULL;
3468
+	}
3469
+
3470
+	/* prepare the entry */
3471
+	if (flags) {
3472
+		/* negative entry */
3473
+		new = dns_cache_mk_bad_entry(&name, type, ttl, flags);
3474
+		if (!new) {
3475
+			rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3476
+			goto error;
3477
+		}
3478
+	} else {
3479
+		if (!old || old->err_flags) {
3480
+			/* there was no matching entry in the hash table,
3481
+			or the entry is a negative record with inefficient space,
3482
+			let us create a new one */
3483
+			switch(type) {
3484
+			case T_A:
3485
+			case T_AAAA:
3486
+				new = dns_cache_mk_ip_entry(&name, ip_addr);
3487
+				if (!new) {
3488
+					rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3489
+					goto error;
3490
+				}
3491
+				/* fix the expiration time, dns_cache_mk_ip_entry() sets it to now-1 */
3492
+				expire = get_ticks_raw() + S_TO_TICKS(ttl);
3493
+				new->expire = expire;
3494
+				new->rr_lst->expire = expire;
3495
+				break;
3496
+			case T_SRV:
3497
+				new = dns_cache_mk_srv_entry(&name, priority, weight, port, &rr_name, ttl);
3498
+				if (!new) {
3499
+					rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3500
+					goto error;
3501
+				}
3502
+			}
3503
+		} else {
3504
+			/* we must modify the entry, so better to clone it, modify the new one,
3505
+			and replace the old with the new entry in the hash table, because the
3506
+			entry is not always locked */
3507
+
3508
+			/* check whether there is an rr with the same value */
3509
+			for (rr=old->rr_lst; rr; rr=rr->next)
3510
+				if ((((type == T_A) || (type == T_AAAA)) &&
3511
+					(memcmp(ip_addr->u.addr, ((struct a_rdata*)rr->rdata)->ip, ip_addr->len)==0))
3512
+				|| ((type == T_SRV) &&
3513
+					(((struct srv_rdata*)rr->rdata)->name_len == rr_name.len) &&
3514
+					(memcmp(rr_name.s, ((struct srv_rdata*)rr->rdata)->name, rr_name.len)==0)))
3515
+				break;
3516
+
3517
+			if (rr) {
3518
+				/* the rr was found in the list */
3519
+				new = dns_cache_clone_entry(old, 0, 0, 0);
3520
+				if (!new) {
3521
+					rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3522
+					goto error;
3523
+				}
3524
+				/* let the rr point to the new structure */
3525
+				rr = (struct dns_rr*)translate_pointer((char*)new, (char*)old, (char*)rr);
3526
+
3527
+				if (type == T_SRV) {
3528
+					/* fix the priority, weight, and port */
3529
+					((struct srv_rdata*)rr->rdata)->priority = priority;
3530
+					((struct srv_rdata*)rr->rdata)->weight = weight;
3531
+					((struct srv_rdata*)rr->rdata)->port = port;
3532
+				}
3533
+
3534
+				/* fix the expire value */
3535
+				rr->expire = get_ticks_raw() + S_TO_TICKS(ttl);
3536
+				new->expire = 0;
3537
+				for (rr=new->rr_lst; rr; rr=rr->next)
3538
+					new->expire = MAX(new->expire, rr->expire);
3539
+			} else {
3540
+				/* there was no matching rr, extend the structure with a new one */
3541
+				switch(type) {
3542
+				case T_A:
3543
+					size = sizeof(struct a_rdata);
3544
+					break;
3545
+				case T_AAAA:
3546
+					size = sizeof(struct aaaa_rdata);
3547
+					break;
3548
+				case T_SRV:
3549
+					size = sizeof(struct srv_rdata)-1 +
3550
+						rr_name.len+1;
3551
+					break;
3552
+				}
3553
+				new = dns_cache_clone_entry(old, size, ttl, &rr);
3554
+				if (!new) {
3555
+					rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3556
+					goto error;
3557
+				}
3558
+			
3559
+				switch(type) {
3560
+				case T_A:
3561
+				case T_AAAA:
3562
+					memcpy(rr->rdata, ip_addr->u.addr, ip_addr->len);
3563
+					break;
3564
+				case T_SRV:
3565
+					((struct srv_rdata*)rr->rdata)->priority = priority;
3566
+					((struct srv_rdata*)rr->rdata)->weight = weight;
3567
+					((struct srv_rdata*)rr->rdata)->port = port;
3568
+					((struct srv_rdata*)rr->rdata)->name_len = rr_name.len;
3569
+					memcpy(((struct srv_rdata*)rr->rdata)->name, rr_name.s, rr_name.len);
3570
+				}
3571
+				/* maximum expire value has been already fixed by dns_cache_clone_entry() */
3572
+			}
3573
+		}
3574
+	}
3575
+	
3576
+	LOCK_DNS_HASH();
3577
+	if (dns_cache_add_unsafe(new)) {
3578
+		rpc->fault(ctx, 400, "Failed to add the entry to the cache");
3579
+		UNLOCK_DNS_HASH();
3580
+		goto error;
3581
+	} else {
3582
+		/* remove the old entry from the list */
3583
+		if (old)
3584
+			_dns_hash_remove(old);
3585
+	}
3586
+	UNLOCK_DNS_HASH();
3587
+
3588
+	if (old)
3589
+		dns_hash_put(old);
3590
+	return;
3591
+
3592
+error:
3593
+	/* leave the old entry in the list, and free the new one */
3594
+	if (old)
3595
+		dns_hash_put(old);
3596
+	if (new)
3597
+		dns_destroy_entry(new);
3598
+}
3599
+
3600
+/* deletes a record from the cache */
3601
+static void dns_cache_delete_record(rpc_t* rpc, void* ctx, unsigned short type)
3602
+{
3603
+	struct dns_hash_entry *e;
3604
+	str name;
3605
+	int err, h, found=0;
3606
+
3607
+	if (rpc->scan(ctx, "S", &name) < 1)
3608
+		return;
3609
+
3610
+	LOCK_DNS_HASH();
3611
+
3612
+	e=_dns_hash_find(&name, type, &h, &err);
3613
+	if (e && (e->type==type)) {
3614
+		_dns_hash_remove(e);
3615
+		found = 1;
3616
+	}
3617
+
3618
+	UNLOCK_DNS_HASH();
3619
+
3620
+	if (!found)
3621
+		rpc->fault(ctx, 400, "Not found");
3622
+}
3623
+
3624
+/* wrapper functions for adding and deleting records */
3625
+void dns_cache_add_a(rpc_t* rpc, void* ctx)
3626
+{
3627
+	dns_cache_add_record(rpc, ctx, T_A);
3628
+}
3629
+
3630
+void dns_cache_add_aaaa(rpc_t* rpc, void* ctx)
3631
+{
3632
+	dns_cache_add_record(rpc, ctx, T_AAAA);
3633
+}
3634
+
3635
+void dns_cache_add_srv(rpc_t* rpc, void* ctx)
3636
+{
3637
+	dns_cache_add_record(rpc, ctx, T_SRV);
3638
+}
3639
+
3640
+void dns_cache_delete_a(rpc_t* rpc, void* ctx)
3641
+{
3642
+	dns_cache_delete_record(rpc, ctx, T_A);
3643
+}
3644
+
3645
+void dns_cache_delete_aaaa(rpc_t* rpc, void* ctx)
3646
+{
3647
+	dns_cache_delete_record(rpc, ctx, T_AAAA);
3648
+}
3649
+
3650
+void dns_cache_delete_srv(rpc_t* rpc, void* ctx)
3651
+{
3652
+	dns_cache_delete_record(rpc, ctx, T_SRV);
3653
+}
3654
+
3655
+
3656
+
3101 3657
 #ifdef DNS_WATCHDOG_SUPPORT
3102 3658
 /* sets the DNS server states */
3103 3659
 void dns_set_server_state_rpc(rpc_t* rpc, void* ctx)
... ...
@@ -313,6 +313,9 @@ inline static int dns_sip_resolve2su(struct dns_srv_handle* h,
313 313
 	return ret;
314 314
 }
315 315
 
316
+/* deletes all the entries from the cache */
317
+void dns_cache_flush(void);
318
+
316 319
 #ifdef DNS_WATCHDOG_SUPPORT
317 320
 /* sets the state of the DNS servers:
318 321
  * 1: at least one server is up