1
/* Copyright (c) 2007-2014 Sam Trenholme
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
15
* This software is provided 'as is' with no guarantees of correctness or
16
* fitness for purpose.
20
#include "DwSys.h" /* So we can log errors */
22
/* Make sure a dw_str object is sane.
23
* Input: Pointer to dw_str
24
* Output: 0 if sane; -1 if not */
26
int dw_assert_sanity(dw_str *object) {
30
if(object->sane != 114) {
33
if(object->str == 0) {
36
if(object->len >= object->max) {
39
if(object->len > 0x0fffffff) {
45
/* Create a new dw_str object.
46
* Input: Maximum length allowed for the string
47
* Output: Pointer to newly created string
49
dw_str *dw_create(uint32_t size) {
51
new = dw_malloc(sizeof(dw_str));
53
return 0; /* We should probably give an "aiee" and
56
if(size >= 134217728 /* 2 ** 27 */) {
60
/* 2 byte cushion to avoid off-by-one security problems */
61
new->str = dw_malloc(size + 2);
72
/* Destroy a dw_str object.
73
* Input: Pointer to string to destroy
74
* Output: 0 on success; -1 on failure
76
int dw_destroy(dw_str *object) {
80
/* Make sure we are, in fact, destroying a dw_str object */
81
if(object->sane != 114) {
84
if(object->str == 0) {
89
/* Reset values just in case we try and use a freed string */
98
/* Add a single character to the DwStr */
100
int dw_addchar(uint8_t add, dw_str *object) {
101
if(dw_assert_sanity(object) == -1) {
104
if(object->max > object->len + 1) {
105
*(object->str + object->len) = add;
113
/* Add a C-string (which may have NULL characters) to a DwStr object.
114
* Input: Pointer to string; number of characters we will add to DwStr
115
* object; pointer to dw_str object. Output: -1 on error; 0 on success */
116
int dw_cstr_append(uint8_t *add, int32_t len, dw_str *obj) {
117
if(dw_assert_sanity(obj) == -1) {
126
if(obj->len + len >= obj->max) { /* Bounds checking */
130
*(obj->str + obj->len) = *add;
138
/* Add a null-terminated string to a DwStr; should the null-terminated string
139
* have the character specified in 'nope', don't append that character and
140
* stop appending to the string. Input: String to append; DwStr to append
141
* to; 'nope' character we're not allowed to add (make this 0 if you want
142
* to allow all non-NULL characters) */
143
int dw_qrappend(uint8_t *add, dw_str *object, char nope) {
144
if(dw_assert_sanity(object) == -1) {
150
while(*add != 0 && *add != nope && object->len < object->max) {
151
*(object->str + object->len) = *add;
159
/* Add an arbitrary null-terminated string of length "len" to a DwStr object */
160
int dw_bin_append(uint8_t *add, int len, dw_str *object) {
161
if(dw_assert_sanity(object) == -1) {
167
while(*add != 0 && len > 0 && object->len < object->max) {
168
*(object->str + object->len) = *add;
175
#endif /* OTHER_STUFF */
178
/* Add a null-terminated string to a DwStr; if the DwStr is non-0 length,
179
* first add a comma. If the null-terminated string has a comma, stop
180
* appending the string.
181
* Input: C string to add; DwStr to add string to
182
* Output: 0 on success; -1 on failure */
183
int dw_qspush(uint8_t *add, dw_str *object) {
184
if(dw_assert_sanity(object) == -1) {
190
/* Add a comma to the end if not first element */
191
if(object->len > 0) {
192
if(dw_addchar(',',object) == -1) {
196
/* Add the string to the end of the string */
197
if(dw_qrappend(add,object,',') == -1) {
202
#endif /* OTHER_STUFF */
205
/* For debug purposes: Output a dw_str object on the standard output. */
206
void dw_stdout(dw_str *object) {
207
uint8_t *look = 0, q = 0;
209
if(dw_assert_sanity(object) == -1) {
210
printf("Object at %p does not look kosher.\n",object);
213
/* We don't need this junk; it just makes it harder to debug */
214
/*printf("Object at %p has length %d, max length %d, and string at %p\n"
215
,object,(int)object->len,(int)object->max,object->str);
216
printf("Object's string is (non-printable-ASCII hex-escaped): ");*/
218
for(p = 0 ; p < object->len; p++) {
220
if(q >= 32 && q <= '~' /* Last ASCII char */) {
223
printf("\\x%02X",q); /* Hex */
224
/* printf(" %d \\x%02X ",p,q); */ /* Hex w/ offset */
225
/*printf("\\%03o",q); */ /* Octal */
231
#endif /* XTRA_STUFF */
233
/* Take some of, or all, of a dw_str, and copy it in to a new dw_str object.
234
* return 0 (NULL) if there is an error copying the string. The parameters
236
* 1) The dw_string we want to copy
237
* 2) The first character we starting copying from. If this value has
238
* a value of 0, then we start copying from the start of the
239
* string. If this has a value of -1, then we start copying at
240
* the end of the string (meaning, we can only copy the very last
241
* character). -2 is the second-to-last character in the string; 1 is
242
* the second character in the string (c indexes, ugh)
243
* 3) The number of characters we copy. 0 means no characters (making
244
* a zero-length string); 1 means 1 character, etc. If this is negative
245
* then we copy relative to the end of the string. In other words, if
246
* the length has a value of -1, we copy until the end of the string;
247
* if length has a value of -2, we copy until the second to last character
248
* in the string, etc.
249
* 4) The maximum allowed length for the string. Should this have a positive
250
* value or 0, the string is allowed to add that many characters to the end
251
* of the string (0: The string can not grow; 1: the string can grow by
252
* one character, etc). If it has a value of -1, then the string has the
253
* same maximum permitted size as the string we are copying. Otherwise,
254
* we return an error.
256
* Output: We create a new dw_str object, which has the copied substr.
258
* Some common parameters: dw_substr(str,0,-1,-1): Copies the entire string
261
dw_str *dw_substr(dw_str *obj, int32_t begin, int32_t amount, int32_t max) {
265
if(dw_assert_sanity(obj) == -1) {
266
goto catch_dw_substr;
269
/* Process negative arguments */
271
begin = obj->len + begin;
274
amount = obj->len - begin + amount + 1;
277
/* Make the string */
279
copy = dw_create(amount + max + 1);
280
} else if(max == -1) {
281
copy = dw_create(obj->max);
283
goto catch_dw_substr;
287
goto catch_dw_substr;
290
/* Do the actual copying */
291
for(c = 0; c < amount; c++) {
292
/* Bounds checking */
293
if(c + begin > obj->len || c >= copy->max) {
296
*(copy->str + c) = *(obj->str + begin + c);
313
/* Read a 16-bit big-endian string that is in a dw_str as a number. DNS
314
* commonly has these kinds of numbers (can you say 1983?)
315
* Input: Pointer to dw_str object; offset where we will look for number
316
* (0 is top of string; -1 is last two bytes of string)
317
* Output: The number; -1 on error */
319
int32_t dw_fetch_u16(dw_str *object, int32_t offset) {
321
if(dw_assert_sanity(object) == -1) {
325
offset = offset + object->len - 1;
327
if(offset + 1 > object->len || offset < 0) {
332
return (*look << 8) | *(look + 1);
335
/* Read a 16-bit big-endian number at the end of a dw_str object, and
336
* remove the string from the string object. -1 on error */
337
int32_t dw_pop_u16(dw_str *object) {
339
if(dw_assert_sanity(object) == -1) {
342
if(object->len < 2) {
345
look = object->str + object->len - 2;
347
return (*look << 8) | *(look + 1);
350
/* Read an 8-bit number at the end of a dw_str object, and
351
* remove the string from the string object. -1 on error */
352
int32_t dw_pop_u8(dw_str *object) {
354
if(dw_assert_sanity(object) == -1) {
357
if(object->len < 1) {
360
look = object->str + object->len - 1;
365
/* Read an 8-bit big-endian string that is in a dw_str as a number.
366
* Input: Pointer to dw_str object; offset where we will look for number
367
* (0 is top of string; negative numbers offsets from end of string [-1
368
* last byte in string, -2 second-to-last byte in string, etc])
369
* Output: The number; -1 on error */
371
int32_t dw_fetch_u8(dw_str *object, int32_t offset) {
373
if(dw_assert_sanity(object) == -1) {
377
offset = object->len + offset;
379
if(offset > object->len || offset < 0) {
387
/* Put a 16-bit big-endian number (the argument "value") in a dw_str object.
388
* Offset can be either a positive or negative number; should offset be
389
* a positive number, then we put that byte in that many bytes from
390
* the beginning of the string. Should offset be a negative number, then
391
* we put the number that many bytes from the end of the string. This
392
* function will, in certain cases make the string one or two bytes longer.
393
* If offset is -1, then the number is added to the end of the string.
394
* If offset is -2, then the number replaces the last byte of the string,
395
* and adds a byte the the end of the string. Should offset be 0, the
396
* number replaces the first two numbers in the string (adding numbers
399
* Should this function succeed, it will return a 0. Otherwise, it
400
* will return a -1 */
402
int dw_put_u16(dw_str *obj, uint16_t value, int32_t offset) {
404
if(dw_assert_sanity(obj) == -1) {
408
/* Process negative offset amount */
410
offset = obj->len + offset + 1;
413
/* We may need to expand the string to fit the number */
414
if(offset > obj->len || obj->len > 0x0fffffff) {
416
} else if(offset >= (int32_t)(obj->len & 0x0ffffff) - 1) { /* -Wall */
418
expand_by = obj->len - offset + 2;
419
if(obj->len + expand_by >= obj->max) {
422
obj->len += expand_by;
423
if(obj->len > obj->max) {
424
obj->len -= expand_by;
429
look = obj->str + offset;
430
*look = (value >> 8) & 0xff;
431
*(look + 1) = value & 0xff;
435
/* Put an 8-bit (the argument "value") in a dw_str object.
436
* Offset can be either a positive or negative number; should offset be
437
* a positive number, then we put that byte in that many bytes from
438
* the beginning of the string. Should offset be a negative number, then
439
* we put the number that many bytes from the end of the string. This
440
* function will, in certain cases make the string one byte longer.
441
* If offset is -1, then the number is added to the end of the string.
443
* Should offset be 0, the number replaces the first number in the string
444
* (adding numbers if needed)
446
* Should this function succeed, it will return a 0. Otherwise, it
449
* BUG: Does not work correctly with length-1 (1-byte) strings
452
int dw_put_u8(dw_str *obj, uint8_t value, int32_t offset) {
454
if(dw_assert_sanity(obj) == -1) {
458
/* Process negative offset amount */
460
offset = obj->len + offset + 1;
463
/* We may need to expand the string to fit the number */
464
if(offset > obj->len || obj->len > 0x0fffffff) {
466
} else if(offset == (int32_t)(obj->len & 0x0ffffff)) { /* -Wall */
468
if(obj->len > obj->max) {
474
look = obj->str + offset;
475
*look = value & 0xff;
480
/* Read a single bit from a dw_str object. The way we choose the bit is
481
* to first choose the byte with the desired bit, then to choose the
482
* bit in that byte. 0 is the least significant (rightmost) bit; 7 is the
483
* most significant bit.
484
* We return -1 on error, 0 if the bit is 0, and 1 if the bit is 1 */
485
int dw_get_bit(dw_str *obj, int32_t byte, int8_t bit) {
488
if(dw_assert_sanity(obj) == -1) {
491
if(byte >= obj->len || byte < 0) {
494
if(bit < 0 || bit > 7) {
497
look = *(obj->str + byte);
500
if((look & a) == a) {
506
#endif /* OTHER_STUFF */
508
/* Compare two dw_string objects to see if they are the same (different max
509
* lengths are allowed). -1 on error, 0 if not the same, and 1 if they are
511
int dw_issame(dw_str *a, dw_str *b) {
513
if(dw_assert_sanity(a) == -1) {
516
if(dw_assert_sanity(b) == -1) {
519
if(a->len != b->len) {
522
for(c = 0; c < a->len; c++) {
523
if(*(a->str + c) != *(b->str + c)) {
530
/* Append one dw_string object to another dw_string.
531
* Input: The two dw_string objects
532
* Output: 0 on success, -1 on error */
533
int dw_append(dw_str *toappend, dw_str *target) {
535
if(dw_assert_sanity(toappend) == -1) {
538
if(dw_assert_sanity(target) == -1) {
541
if(target->len + toappend->len >= target->max) {
544
for(c = 0; c < toappend->len; c++) {
545
*(target->str + target->len + c) = *(toappend->str + c);
547
target->len += toappend->len;
551
/* Append a substring of one dw_string object to another dw_string.
552
* Input: String we splice from, where we start cutting from that string,
553
* how many bytes to cut from said string, the string to append to
554
* Output: 0 on success, -1 on error
556
int dw_substr_append(dw_str *splice, int32_t begin, int32_t amount,
560
tmp = dw_substr(splice, begin, amount, 1);
565
if(dw_append(tmp,target) == -1) {
574
/* Copy a dw_string object in to a null-terminated C-string.
575
* Input: The string to convert
576
* Output: A pointer to a newly created C-string; 0 on error */
578
uint8_t *dw_to_cstr(dw_str *obj) {
582
if(dw_assert_sanity(obj) == -1) {
586
out = dw_malloc(obj->len + 3);
587
for(a = 0; a < obj->len; a++) {
588
*(out + a) = *(obj->str + a);
590
*(out + a) = 0; /* Null-terminated */
595
/* Find the last instance of a given character in a DwStr object.
596
* Input: The dw_str object, the character we are seeking
597
* Output: The index in the string with the character in question
598
* -1 on error; -2 on "not found"
601
int32_t dw_rfind(dw_str *obj, uint8_t rx) {
604
if(dw_assert_sanity(obj) == -1) {
610
/* We will never find the char in a 0-length string */
618
while(index >= 0 && *(obj->str + index) != rx) {
630
/* Take the last element of a comma-separated DwStr object, remove it
631
* from said string, and create a new string with the popped comma-separated
632
* object. Should the source string not have a comma in it, then we take
633
* the entire source string, blank it (make it 0-length) and copy it over
634
* to the newly created string. The final comma is removed from the
635
* source string, but is *not* included in the destination string.
636
* Input: The source string
637
* Output: A newly created string with the last comma separated object */
639
dw_str *dw_qspop(dw_str *in) {
644
if(dw_assert_sanity(in) == -1) {
648
index = dw_rfind(in,',');
650
if(index == -2) { /* Not found */
654
} else if(index < 0) { /* Error during seek */
659
index++; /* We don't include ',' in copied string */
661
if(len < 0) { /* Sanity check */
664
out = dw_substr(in,index,len,1);
666
if(in->len >= in->max) {
682
/* Create a copy of a dw_str object with any leading whitespace in the
683
* original object removed in the copy. If the original is nothing
684
* but whitespace, the copy will be a 0-length string.
685
* Input: dw_str object we want to remove leading whitespace from
686
* Output: Newly created dw_str object without the leading whitespace */
688
dw_str *dw_zap_lws(dw_str *obj) {
692
if(dw_assert_sanity(obj) == -1) {
693
goto catch_dw_zap_lws;
696
while(index < obj->len &&
697
(*(obj->str + index) == ' ' || *(obj->str + index) == '\t') ) {
701
if(index >= obj->len) { /* Obj is nothing but whitespace (or 0-len) */
706
out = dw_substr(obj,index,-1,1);
717
/* Convert a dw_str object with a number in to an integer. Leading
718
* whitespace is ignored; anything that is not a number or letter stops
721
* obj: The dw_str object we convert in to a number
722
* index: How far in to the string we begin conversion (0 is
723
* beginning of string)
724
* base: The base we work in (2 is binary, 10 is decimal, 16 is
725
* hex; this can be up to 36)
727
* The number the string represents; -1 on error
730
int32_t dw_atoi(dw_str *obj, int32_t index, int base) {
732
int num = 0, counter = 0;
734
if(dw_assert_sanity(obj) == -1) {
737
if(base < 2 || base > 36) {
740
if(index < 0 || index >= obj->len) {
743
look = *(obj->str + index);
744
while(index < obj->len && (look == ' ' || look == '\t')) {
746
look = *(obj->str + index);
748
for(counter = 0; counter < 100; counter++) {
749
if(index >= obj->len) {
752
look = *(obj->str + index);
753
if(look >= '0' && look <= '9') {
755
} else if(look >= 'a' && look <= 'z') {
756
num = look - 'a' + 10;
757
} else if(look >= 'A' && look <= 'Z') {
758
num = look - 'A' + 10;
773
/* This extracts just a DNS DNAME (without TYPE) from a raw c-string (with
774
* ASCII nulls, since DNS packets have those) and puts it in a newly
776
* Input: Pointer to raw string; offset where we look for DNS DNAME,
777
* maximum length of raw string
778
* Output: A pointer to a new dw_str with NAME
780
dw_str *dw_get_dname(uint8_t *raw, int offset, int max) {
781
int len = 0, counter = 0;
786
out = dw_create(max);
788
out = dw_create(260);
791
if(out == 0 || raw == 0) {
792
goto catch_dw_get_dname;
795
for(counter = 0; counter < 400; counter++) {
796
if(offset >= max - 2 || soffset > 255) {
797
goto catch_dw_get_dname;
800
len = *(raw + offset);
801
if(len > 63 || len < 0) { /* No compression pointers */
802
goto catch_dw_get_dname;
805
*(out->str + soffset) = len;
806
if(len == 0) { /* End of dlabel */
813
if(offset >= max - 2 || soffset > 255) {
814
goto catch_dw_get_dname;
816
*(out->str + soffset) = *(raw + offset);
817
/* No ASCII control characters in DNS names */
818
if(*(out->str + soffset) < 32) {
819
goto catch_dw_get_dname;
825
out->len = soffset + 1;
835
/* This extracts a DNS DNAME, followed by a two-byte TYPE (the type of RR)
836
* from a raw c-string (with ASCII nulls, since DNS packets have those)
837
* and puts it in a newly created string.
838
* Input: Pointer to raw string; offset where we look for DNS DNAME + TYPE,
839
* maximum length of raw string
840
* Output: A pointer to a new dw_str with NAME + TYPE
842
dw_str *dw_get_dname_type(uint8_t *raw, int offset, int max) {
845
out = dw_get_dname(raw,offset,max);
847
goto catch_dw_get_dname_class;
851
/* Accoring to http://www.iana.org/assignments/dns-parameters,
852
* records 65280 (0xff00) to 65535 (0xfffe) are "private use";
853
* Deadwood uses 65392 - 65407 for internal use and will not
854
* accept queries with these numbers in place; see
855
* doc/internals/RR.Allocation for details on how Deadwood uses
856
* these RR numbers */
857
if(*(raw + offset)==0xff && (*(raw + offset + 1) & 0xf0)==0x70) {
858
goto catch_dw_get_dname_class;
860
*(out->str + out->len) = *(raw + offset);
861
*(out->str + out->len + 1) = *(raw + offset + 1);
865
catch_dw_get_dname_class:
873
/* Determine where the end of a <domain-name> at offset in the string
874
* is (ugh, DNS is ugly); -1 on error */
875
int32_t dw_get_dn_end(dw_str *in, int offset) {
876
int len = 0, counter = 0;
878
if(dw_assert_sanity(in) == -1) {
882
for(counter = 0; counter < 200; counter++) {
883
if(offset + 1 > in->len) {
887
len = *(in->str + offset);
888
if(len >= 192) { /* Compression pointer */
891
} else if(len > 63 || len < 0) { /* Invalid length */
893
} else if(len == 0) { /* End of dlabel */
903
/* Get a TTL that is buried in a DNS string. We start at the beginning of
904
* the DNS name, figure out how long the name is (ugh), then skip past
905
* type and class to get the TTL; return -1 on error. We don't support
906
* TTLs longer than 31,536,000: One year (0x01E13380)
908
* Input: String we will get TTL from; offset from where we will get TTL,
909
* maximum allowed TTL (which should be 31536000 when called from
910
* another part of Deadwood), recursion depth (to stop infinite loops)
911
* Note that depth is a positive number that decrements.
913
int32_t dw_get_a_dnsttl(dw_str *in, int offset, int32_t max, int depth) {
914
int32_t out = 0, type = 0;
917
if(dw_assert_sanity(in) == -1) {
921
if(depth <= 0) { /* End of packet/Depth exceeded */
929
offset = dw_get_dn_end(in,offset);
931
if(offset < 0 || (offset + 8) > in->len) {
935
raw = (in->str + offset);
937
/* Get record type (A, CNAME, etc.) */
938
type = ((int32_t)*(raw + 0) << 8) | ((int32_t)*(raw + 1));
940
if(*(raw + 4) > 0x7f) {
941
return 31536000; /* TTL out of bounds */
943
out = ((int32_t)*(raw + 4)<< 24) |
944
((int32_t)*(raw + 5) << 16) |
945
((int32_t)*(raw + 6) << 8) |
946
((int32_t)*(raw + 7));
949
} else if(out > max) {
953
if(type == 5 /* CNAME */) {
954
offset = dw_get_dn_end(in,offset + 10);
955
if(offset < 0 || offset > in->len) {
958
return dw_get_a_dnsttl(in,offset,out,depth - 1);
965
/* Given a dw_str object, where the dw_str is a raw DNS packet, determine
966
* the TTL for the packet. Note that this only looks at the TTL for the
967
* first RR in a reply. Things like "www.foo.bar. +86400 CNAME www.baz.bar. ~
968
* www.baz.bar. +3600 192.168.42.102" will have the entire record cached
969
* for a day (86400 seconds).
971
* Note that this routine is currenly not used by any other program.
973
int32_t dw_get_ttl_from_packet(dw_str *in) {
976
if(dw_assert_sanity(in) == -1) {
984
offset = dw_get_dn_end(in,12);
986
if(offset < 0 || offset > in->len) {
990
/* BUG: This will not work with packets with only CNAME answers */
991
return dw_get_a_dnsttl(in,offset,31536000,32);
993
#endif /* OTHER_STUFF */
995
/* Given a packet in the form put in the DNS cache (with things like type,
996
* ancount, nscount, and arcount at the end of the string), tell the user how
997
* many answers are in the packet. */
998
int32_t dw_cachepacket_to_ancount(dw_str *packet) {
1001
if(dw_assert_sanity(packet) == -1 || packet->len < 7) {
1005
/* A cachepacket string is in the format
1006
* <packet><ancount><nscount><arcount><type>, where all numbers
1007
* are 16-bit, except for <type> which is 8-bit */
1009
offset = packet->len - 7;
1011
return dw_fetch_u16(packet,offset);
1014
/* Given a raw pointer to a c-string (which can have NULLs), and a length
1015
* for that string, extract a dw_str object that is a cachable form of
1016
* the packet. Basically:
1017
* * Everything after the question is put at the beginning
1019
* * This is followed by, in order, ancount, nscount, then
1020
* arcount, and finally the 8-bit "type"
1023
dw_str *dw_packet_to_cache(uint8_t *raw, int len, uint8_t type) {
1024
int32_t ancount = 0, nscount = 0, arcount = 0;
1025
dw_str *hack = 0, *out = 0;
1028
/* A very ugly, but fast, way to make recvfrom()'s str/len pair
1029
* in to a dw_str object. */
1030
hack = dw_malloc(sizeof(dw_str));
1031
hack->max = len + 1;
1033
hack->str = (uint8_t *)raw;
1036
ancount = dw_fetch_u16(hack,6);
1037
nscount = dw_fetch_u16(hack,8);
1038
arcount = dw_fetch_u16(hack,10);
1040
if(ancount < 0 || nscount < 0 || arcount < 0) {
1041
goto catch_dw_packet_to_cache;
1044
/* OK, hunt for the beginning of the packet */
1045
offset = dw_get_dn_end(hack,12);
1047
goto catch_dw_packet_to_cache;
1050
out = dw_substr(hack,offset,-1,7);
1051
dw_put_u16(out,ancount,-1);
1052
dw_put_u16(out,nscount,-1);
1053
dw_put_u16(out,arcount,-1);
1054
dw_addchar(type,out);
1058
catch_dw_packet_to_cache:
1070
/* Make sure a filename is sanitized; only lowercase letters, the '_',
1071
* the '-', and the '/' are allowed in file names; anything else becomes
1073
int dw_filename_sanitize(dw_str *obj) {
1077
if(dw_assert_sanity(obj) == -1) {
1081
for(index = 0; index < obj->len; index++) {
1082
look = *(obj->str + index);
1083
if((look < 'a' || look > 'z') && look != '/' &&
1084
look != '-' && look != '_') {
1085
*(obj->str + index) = '_';
1092
/* See if a given ASCII name ends in a '.'; if it doesn't return -1, if
1093
* there is an unexpected error, return 0, and if it does end with '.', return
1095
int dw_ends_in_dot(dw_str *in) {
1096
if(dw_assert_sanity(in) == -1) {
1104
if(*(in->str + in->len - 1) != '.') {
1111
/* Used by dw_dnsname_convert, this part of the code converts DNS name
1112
* delimiters in the name (usually dots) into DNS' peculiar length
1113
* names. It only does things one character at a time.
1115
* Input: String to convert, output string to convert to, offset to
1116
* convert at, place where the last delimiter was, pointer to "count"
1117
* of characters in this label, character to use as delimiter
1119
* Output: New location of delimiter
1122
int dw_dnsname_delim_convert(dw_str *in, dw_str *out, int a, int place,
1123
int *count, uint8_t delim) {
1125
if(*(in->str + a) == delim) {
1127
return -1; /* bad label */
1129
if(place < out->max) {
1130
*(out->str + place) = *count;
1136
if(a + 1 < out->max) {
1137
*(out->str + a + 1) = *(in->str + a);
1140
return -1; /* Label too long */
1147
/* Convert an ASCII name, like "www.samiam.org." in to the DNS form of the
1148
* same name (\003www\006samiam\003org\000). Output, as a new string, the
1149
* newly created DNS string; 0 if there is any error */
1150
dw_str *dw_dnsname_convert(dw_str *in) {
1152
int c = 0, place = 0, a = 0;
1154
if(dw_assert_sanity(in) == -1) {
1158
if(dw_ends_in_dot(in) != 1) {
1162
out = dw_create(in->len + 4); /* Cushion to fit 2-byte qtype */
1166
out->len = in->len + 1;
1168
if(*(in->str) == '.') {
1170
goto catch_dw_dnsname_convert; /* bad label */
1179
for(a = 0 ; a < in->len ; a++) {
1180
place = dw_dnsname_delim_convert(in, out, a, place, &c, '.');
1182
goto catch_dw_dnsname_convert;
1186
if(out->len - 1 < out->max) {
1187
*(out->str + out->len - 1) = 0; /* Final "dot" in hostname */
1191
catch_dw_dnsname_convert:
1198
/* Chop off the first label of a DNS name; for example, the raw DNS form
1199
* of www.example.com. (\003www\007example\003com\000) becomes example.com
1200
* (\007example\003com\000). This will also work with strings having data
1201
* after the end of the DNS name.
1203
* This function creates a new string which needs to be freed by its caller
1205
dw_str *dw_dnslabel_chop(dw_str *in) {
1207
int offset = 0, a = 0, b = 0;
1209
if(dw_assert_sanity(in) == -1) {
1216
offset = *(in->str);
1217
if(offset < 1 || offset > 63) {
1220
if(in->len < offset) {
1224
out = dw_create(in->len - offset + 1);
1231
while(a < in->len && b < out->max) {
1232
*(out->str + b) = *(in->str + a);
1242
/* Rotate data in a string: Given a start point and a pivot point, take all of
1243
* the string between the pivot point to the end, and put it where the start
1244
* point is. Take all the data from the start point to the pivot point, and
1245
* put it at the end of the string.
1247
* For example, if we have the string "0123456789", and the start is 3, and
1248
* the pivot 5, we would have the string "0125678934" after running
1252
int dw_rotate(dw_str *in, int32_t start, int32_t pivot, int32_t end) {
1253
dw_str *part1 = 0, *part2 = 0, *part3 = 0;
1255
if(in == 0 || start >= pivot || pivot >= end || end >= in->len) {
1259
part1 = dw_substr(in,start,pivot - start,1);
1263
part2 = dw_substr(in,pivot,end - pivot,1);
1268
part3 = dw_substr(in,end,-1,1);
1275
dw_append(part2,in);
1276
dw_append(part1,in);
1277
dw_append(part3,in);