this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 326d319fb839aaf8ed5dfba3af3a6c13108388ee 158 lines 5.2 kB view raw
1const std = @import("std"); 2 3pub const BytePacketBuffer = struct { 4 buf: [512]u8 = undefined, 5 pos: usize = 0, 6 7 /// Change the buffer position forward a specific number of steps 8 pub fn step(self: *BytePacketBuffer, pos: usize) void { 9 self.pos += pos; 10 } 11 12 /// Chanke the buffer position 13 pub fn seek(self: *BytePacketBuffer, pos: usize) void { 14 self.pos = pos; 15 } 16 17 /// Read a single byte and move the position one step forward 18 pub fn read(self: *BytePacketBuffer) error{EndOfBuffer}!u8 { 19 if (self.pos >= comptime self.buf.len) return error.EndOfBuffer; 20 const res = self.buf[self.pos]; 21 self.pos += 1; 22 return res; 23 } 24 25 /// Get a single byte without changing the buffer position 26 pub fn get(self: *const BytePacketBuffer, pos: usize) error{EndOfBuffer}!u8 { 27 if (pos >= comptime self.buf.len) return error.EndOfBuffer; 28 return self.buf[pos]; 29 } 30 31 /// Get a range of bytes 32 pub fn get_range(self: *const BytePacketBuffer, start: usize, len: usize) error{EndOfBuffer}![]const u8 { 33 if (start + len >= comptime self.buf.len) return error.EndOfBuffer; 34 return self.buf[start .. start + len]; 35 } 36 37 /// Read two bytes, stepping two steps forward 38 pub fn read_u16(self: *BytePacketBuffer) error{EndOfBuffer}!u16 { 39 return (@as(u16, try self.read()) << 8) | 40 @as(u16, try self.read()); 41 } 42 43 /// Read two bytes, stepping two steps forward 44 pub fn read_u32(self: *BytePacketBuffer) error{EndOfBuffer}!u32 { 45 return @as(u32, try self.read()) << 24 | 46 (@as(u32, try self.read()) << 16) | 47 (@as(u32, try self.read()) << 8) | 48 (@as(u32, try self.read())); 49 } 50 51 /// Read a qname 52 /// 53 /// The tricky part: Reading domain names, taking labels into consideration. 54 /// Will take something like [3]www[6]google[3]com and append 55 /// www.google.com to outstr. 56 pub fn read_qname(self: *BytePacketBuffer, outstr: []u8) !void { 57 // We might encounter jumps, therefore we need to keep thrack of our position locally 58 var pos = self.pos; 59 var out_pos: usize = 0; 60 61 // track whether or nor we've jumped 62 var jumped = false; 63 const max_jumps: usize = 5; 64 var jumps_performed: usize = 0; 65 66 var delim: ?[]const u8 = null; 67 while (true) { 68 if (jumps_performed > max_jumps) return error.JumpLimitExceeded; 69 70 // Each label starts with a length byte 71 const len = try self.get(pos); 72 73 // If len has the two most signigicant bit set, it represents a jump to some other 74 // offset in the packet: 75 if ((len & 0xC0) == 0xC0) { 76 // Update the buffer position to a point past the current label 77 if (!jumped) self.seek(2); 78 79 // Read another byte, calculate offset and performe the jump by updating our 80 // local position variable 81 const b2 = @as(u16, try self.get(pos + 1)); 82 const offset = ((@as(u16, len) ^ 0xC0) << 8) | b2; 83 pos = @as(usize, offset); 84 85 // Indicate that a jump was performed 86 jumped = true; 87 jumps_performed += 1; 88 89 continue; 90 } else { 91 // Move a single byte forward to move path the length 92 pos += 1; 93 94 // Domain names are terminated by an empty label of length 0, so if the length 95 // is zero we're done 96 if (len == 0) break; 97 98 if (delim) |del| { 99 @memcpy(outstr[out_pos .. out_pos + del.len], del); 100 out_pos += del.len; 101 } 102 103 @memcpy(outstr[out_pos .. out_pos + len], try self.get_range(pos, len)); 104 delim = "."; 105 106 pos += len; 107 out_pos += len; 108 } 109 } 110 111 if (!jumped) self.seek(1); 112 } 113}; 114 115test "BytePacketBuffer.read" { 116 const testing = std.testing; 117 var buf = BytePacketBuffer{}; 118 buf.buf[0] = 0x1; 119 try testing.expectEqual(0x1, try buf.read()); 120} 121 122test "BytePacketBuffer.read_u16" { 123 const testing = std.testing; 124 var buf = BytePacketBuffer{}; 125 buf.buf[0] = 0x1; 126 buf.buf[1] = 0x1; 127 try testing.expectEqual(0x101, try buf.read_u16()); 128} 129 130test "BytePacketBuffer.read_u32" { 131 const testing = std.testing; 132 var buf = BytePacketBuffer{}; 133 buf.buf[0] = 0x1; 134 buf.buf[1] = 0x1; 135 buf.buf[2] = 0x1; 136 buf.buf[3] = 0x1; 137 try testing.expectEqual(0x1010101, try buf.read_u32()); 138} 139 140test "BytePacketBuffer.read_qname" { 141 const testing = std.testing; 142 const allocator = testing.allocator; 143 144 const input = [_]u8{ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00 }; 145 var buf = BytePacketBuffer{}; 146 147 for (input, 0..) |char, idx| { 148 buf.buf[idx] = char; 149 } 150 151 const expected = "google.com"; 152 const outstr = try allocator.alloc(u8, expected.len); 153 defer allocator.free(outstr); 154 155 try buf.read_qname(outstr); 156 157 try testing.expectEqualStrings(expected, outstr); 158}