rust-dnsbox/lib/dnsbox-base/src/common_types/time/mod.rs

79 lines
2.2 KiB
Rust

use bytes::Bytes;
use errors::*;
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
use std::fmt;
use std::io::Cursor;
mod epoch;
/// timestamp in seconds since epoch (ignoring leap seconds)
///
/// Is expected to wrap around.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Time(pub u32);
impl DnsPacketData for Time {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
Ok(Time(DnsPacketData::deserialize(data)?))
}
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
self.0.serialize(context, packet)
}
}
impl DnsTextData for Time {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
let field = next_field(data)?;
let epoch = field.parse::<u32>();
if field.len() == 14 && epoch.is_err() {
let tm = epoch::Tm::parse_YYYYMMDDHHmmSS(field)?;
Ok(Time(tm.epoch() as u32))
} else {
Ok(Time(epoch?))
}
}
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
epoch::Tm::from_epoch(self.0 as i64).unwrap().format_YYYYMMDDHHmmSS(&mut*f.format_field()?)
// write!(f, "{}", self.0)
}
}
pub const TIME48_MAX: u64 = 0xffff_ffff_ffff;
/// 48-bit timestamp in seconds since epoch (ignoring leap seconds)
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Time48(pub u64);
impl DnsPacketData for Time48 {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
let high16 = u16::deserialize(data)? as u64;
let low32 = u32::deserialize(data)? as u64;
Ok(Time48(high16 | low32))
}
fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
ensure!(self.0 <= TIME48_MAX, "time48 overflow");
let high16 = (self.0 >> 32) as u16;
let low32 = self.0 as u32;
high16.serialize(context, packet)?;
low32.serialize(context, packet)?;
Ok(())
}
}
impl DnsTextData for Time48 {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
let field = next_field(data)?;
let epoch = field.parse::<u64>()?;
ensure!(epoch <= TIME48_MAX, "time48 overflow");
Ok(Time48(epoch))
}
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}