pub struct PacketBuilderStep<LastStep> { /* private fields */ }
Available on crate feature std only.
Expand description

An unfinished packet that is build with the packet builder

Implementations§

source§

impl PacketBuilderStep<Ethernet2Header>

source

pub fn ipv4( self, source: [u8; 4], destination: [u8; 4], time_to_live: u8 ) -> PacketBuilderStep<IpHeaders>

Add an IPv4 header

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
   .ipv4([192,168,1,1], //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .udp(21,    //source port
        1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn ip(self, ip_header: IpHeaders) -> PacketBuilderStep<IpHeaders>

Add an IP header (length, protocol/next_header & checksum fields will be overwritten based on the rest of the packet).

§Examples

With an IPv4 header:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],
              [7,8,9,10,11,12])
   //payload_len, protocol & checksum will be replaced during write
   .ip(IpHeaders::Ipv4(
       Ipv4Header::new(
           0, //payload_len will be replaced during write
           12, //time_to_live
           ip_number::UDP, //will be replaced during write
           [0,1,2,3], //source
           [4,5,6,7] //destination
       ).unwrap(),
       Default::default()));

With an IPv6 header:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],
              [7,8,9,10,11,12])
   .ip(IpHeaders::Ipv6(
        Ipv6Header{
            traffic_class: 0,
            flow_label: 0.try_into().unwrap(),
            hop_limit: 4,
            source: [0;16],
            destination: [0;16],
            // payload_length & next_header will be replaced during write
            ..Default::default()
        },
        Default::default()));
source

pub fn ipv6( self, source: [u8; 16], destination: [u8; 16], hop_limit: u8 ) -> PacketBuilderStep<IpHeaders>

Add an IPv6 header

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],
              [7,8,9,10,11,12])
    .ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
   .udp(21,    //source port
        1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn vlan(self, vlan: VlanHeader) -> PacketBuilderStep<VlanHeader>

Adds a vlan tagging header with the given vlan identifier

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
    .vlan(VlanHeader::Single(
        SingleVlanHeader{
            pcp: 1.try_into().unwrap(),
            drop_eligible_indicator: false,
            vlan_id: 0x123.try_into().unwrap(),
            ether_type: 0.into() // will be overwritten during write
        }))
    .ipv4([192,168,1,1], //source ip
          [192,168,1,2], //destination ip
          20)            //time to life
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn single_vlan( self, vlan_identifier: VlanId ) -> PacketBuilderStep<VlanHeader>

Adds a vlan tagging header with the given vlan identifier

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
    .single_vlan(0x123.try_into().unwrap()) // vlan identifier
    .ipv4([192,168,1,1], //source ip
          [192,168,1,2], //destination ip
          20)            //time to life
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn double_vlan( self, outer_vlan_identifier: VlanId, inner_vlan_identifier: VlanId ) -> PacketBuilderStep<VlanHeader>

Adds two vlan tagging header with the given vlan identifiers (also known as double vlan tagging).

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
    .double_vlan(0x123.try_into().unwrap(), // outer vlan identifier
                 0x234.try_into().unwrap()) // inner vlan identifier
    .ipv4([192,168,1,1], //source ip
          [192,168,1,2], //destination ip
          20)            //time to life
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source§

impl PacketBuilderStep<VlanHeader>

source

pub fn ip(self, ip_header: IpHeaders) -> PacketBuilderStep<IpHeaders>

Add an ip header (length, protocol/next_header & checksum fields will be overwritten based on the rest of the packet).

§Example IPv4
let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],
              [7,8,9,10,11,12])
   .single_vlan(0x132.try_into().unwrap())
   //payload_len, protocol & checksum will be replaced during write
   .ip(IpHeaders::Ipv4(
        Ipv4Header::new(
            0, //payload_len will be replaced during write
            12, //time_to_live
            ip_number::UDP, //will be replaced during write
            [0,1,2,3], //source
            [4,5,6,7] //destination
        ).unwrap(),
        Default::default() // IPv4 extension headers (default is none)
    ));
§Example IPv6
let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],
              [7,8,9,10,11,12])
   .single_vlan(0x132.try_into().unwrap())
   .ip(IpHeaders::Ipv6(
        Ipv6Header{
            traffic_class: 0,
            flow_label: 0.try_into().unwrap(),
            hop_limit: 4,
            source: [0;16],
            destination: [0;16],
            // payload_length & next_header will be replaced during write
            ..Default::default()
        },
        Default::default() // IPv6 extension headers (default is none)
    ));
source

pub fn ipv6( self, source: [u8; 16], destination: [u8; 16], hop_limit: u8 ) -> PacketBuilderStep<IpHeaders>

Add an IPv6 header

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
    .single_vlan(0x123.try_into().unwrap()) // vlan identifier
    .ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn ipv4( self, source: [u8; 4], destination: [u8; 4], time_to_live: u8 ) -> PacketBuilderStep<IpHeaders>

Add an IPv4 header

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
    .single_vlan(0x123.try_into().unwrap()) // vlan identifier
    .ipv4([192,168,1,1], //source ip
          [192,168,1,2], //destination ip
          20)            //time to life
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source§

impl PacketBuilderStep<IpHeaders>

source

pub fn icmpv4(self, icmp_type: Icmpv4Type) -> PacketBuilderStep<Icmpv4Header>

Adds an ICMPv4 header of the given Icmpv4Type to the packet.

If an ICMPv4 header gets added the payload used during the builders write call contains the bytes after the header and has different meanings and contents based on the type. Usually all statically sized values known based on the ICMPv4 type & code are part of the header and the payload is used to store contains the dynamic parts of the ICMPv4 packet.

Check Icmpv4Type for a documentation which values are part of the header and what is stored as part of the payload.

§Example

Basic usage:

let builder = PacketBuilder::
   ipv4([192,168,1,1],  //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .icmpv4(
        Icmpv4Type::TimeExceeded(
            icmpv4::TimeExceededCode::TtlExceededInTransit
        )
    );

// what is part of the payload depends on the Icmpv4Type
//
// In case of `Icmpv4Type::TimeExceeded` the "internet header
// + 64 bits of the original data datagram" should be given as
// the payload
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv4_raw( self, type_u8: u8, code_u8: u8, bytes5to8: [u8; 4] ) -> PacketBuilderStep<Icmpv4Header>

Adds an ICMPv4 header based on raw numbers.

This can be useful when trying to build an ICMPv4 packet which is not fully supported by etherparse and is the equivalent of using Icmpv4Type::Unknown together with PacketBuilderStep<IpHeaders>::icmpv4.

§Example

Basic usage:

let builder = PacketBuilder::
   ipv4([192,168,1,1],  //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .icmpv4_raw(
        253, // ICMPv4 type (e.g. 253 is RFC3692-style Experiment 1)
        0, // ICMPv4 code
        [1,2,3,4]  // bytes 5-8 in the ICMPv4 header
    );

// the payload is written after the 8 byte raw ICMPv4 header
let payload = [1,2,3,4,5,6,7,8];

// get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

// serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv4_echo_request( self, id: u16, seq: u16 ) -> PacketBuilderStep<Icmpv4Header>

Adds an ICMPv4 echo request packet.

§Example

Basic usage:

let builder = PacketBuilder::
   ipv4([192,168,1,1],  //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .icmpv4_echo_request(
        123, // identifier
        456, // sequence number
    );

// payload of the echo request
let payload = [1,2,3,4,5,6,7,8];

// get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

// serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv4_echo_reply( self, id: u16, seq: u16 ) -> PacketBuilderStep<Icmpv4Header>

Adds an ICMPv4 echo reply packet.

§Example

Basic usage:

let builder = PacketBuilder::
   ipv4([192,168,1,1],  //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .icmpv4_echo_reply(
        123, // identifier
        456, // sequence number
    );

// payload of the echo reply
let payload = [1,2,3,4,5,6,7,8];

// get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

// serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv6(self, icmp_type: Icmpv6Type) -> PacketBuilderStep<Icmpv6Header>

Adds an ICMPv6 header of the given Icmpv6Type to the packet.

If an ICMPv6 header gets added the payload used during the builders write call contains the bytes after the header and has different meanings and contents based on the type. Usually all statically sized values known based on the ICMPv6 type & code are part of the header and the payload is used to store contains the dynamic parts of the ICMPv6 packet.

Check Icmpv6Type for a documentation which values are part of the header and what is stored as part of the payload.

§Example

Basic usage:

let builder = PacketBuilder::
    ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
   .icmpv6(
        Icmpv6Type::TimeExceeded(
            icmpv6::TimeExceededCode::HopLimitExceeded
        )
    );

// what is part of the payload depends on the Icmpv6Type
//
// In case of `Icmpv6Type::TimeExceeded` "As much of invoking packet
// as possible without the ICMPv6 packet exceeding the minimum IPv6 MTU"
// should be given as the payload.
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv6_raw( self, type_u8: u8, code_u8: u8, bytes5to8: [u8; 4] ) -> PacketBuilderStep<Icmpv6Header>

Adds an ICMPv6 header based on raw values.

This can be useful when trying to build an ICMPv6 packet which is not fully supported by etherparse and is the equivalent of using Icmpv6Type::Unknown together with PacketBuilderStep<IpHeaders>::icmpv6.

§Example

Basic usage:

let builder = PacketBuilder::
    ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
   .icmpv4_raw(
        200, // ICMPv6 type (e.g. 200 is for "private experimentation")
        0, // ICMPv6 code
        [1,2,3,4]  // bytes 5-8 in the ICMPv6 header
    );

// the payload is written after the 8 byte raw ICMPv6 header
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv6_echo_request( self, id: u16, seq: u16 ) -> PacketBuilderStep<Icmpv6Header>

Adds an ICMPv6 echo reply packet.

§Example

Basic usage:

let builder = PacketBuilder::
    ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
   .icmpv6_echo_request(
        123, // identifier
        456, // sequence number
    );

// payload of the echo request
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn icmpv6_echo_reply( self, id: u16, seq: u16 ) -> PacketBuilderStep<Icmpv6Header>

Adds an ICMPv6 echo request packet.

§Example

Basic usage:

let builder = PacketBuilder::
    ipv6(
        //source
        [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26],
        //destination
        [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],
        //hop_limit
        47)
   .icmpv6_echo_reply(
        123, // identifier
        456, // sequence number
    );

// payload of the echo reply
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn udp( self, source_port: u16, destination_port: u16 ) -> PacketBuilderStep<UdpHeader>

Adds an UDP header.

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
              [7,8,9,10,11,12]) //destination mac
   .ipv4([192,168,1,1], //source ip
         [192,168,1,2], //destination ip
         20)            //time to life
   .udp(21,    //source port
        1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn tcp( self, source_port: u16, destination_port: u16, sequence_number: u32, window_size: u16 ) -> PacketBuilderStep<TcpHeader>

Adds a simple TCP header.

§Example

Basic usage:

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     // source mac
              [7,8,9,10,11,12]) // destination mac
   .ipv4([192,168,1,1], // source ip
         [192,168,1,2], // destination ip
         20)            // time to life
   .tcp(21,    // source port
        12,    // destination port
        12345, // sequence number
        4000); // window size

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn tcp_header(self, tcp_header: TcpHeader) -> PacketBuilderStep<TcpHeader>

Adds a more complicated TCP header.

§Example

Basic usage:

use etherparse::TcpHeader;

let mut tcp_header = TcpHeader::new(
    21,     // source port
    12,     // destination port
    12345,  // sequence number
    4000,   // window size
);
tcp_header.psh = true;
tcp_header.ack = true;
tcp_header.acknowledgment_number = 1;

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     // source mac
              [7,8,9,10,11,12]) // destination mac
   .ipv4([192,168,1,1], // source ip
         [192,168,1,2], // destination ip
         20)            // time to life
   .tcp_header(tcp_header);

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(
                    builder.size(payload.len()));

//serialize
builder.write(&mut result, &payload).unwrap();
source

pub fn write<T: Write + Sized>( self, writer: &mut T, last_next_header_ip_number: IpNumber, payload: &[u8] ) -> Result<(), BuildWriteError>

Write all the headers and the payload with the given ip number.

last_next_header_ip_number will be set in the last extension header or if no extension header exists the ip header as the “next header” or “protocol number”.

source

pub fn size(&self, payload_size: usize) -> usize

Returns the size of the packet when it is serialized

source§

impl PacketBuilderStep<Icmpv4Header>

source

pub fn write<T: Write + Sized>( self, writer: &mut T, payload: &[u8] ) -> Result<(), BuildWriteError>

Write all the headers and the payload.

source

pub fn size(&self, payload_size: usize) -> usize

Returns the size of the packet when it is serialized

source§

impl PacketBuilderStep<Icmpv6Header>

source

pub fn write<T: Write + Sized>( self, writer: &mut T, payload: &[u8] ) -> Result<(), BuildWriteError>

Write all the headers and the payload.

source

pub fn size(&self, payload_size: usize) -> usize

Returns the size of the packet when it is serialized

source§

impl PacketBuilderStep<UdpHeader>

source

pub fn write<T: Write + Sized>( self, writer: &mut T, payload: &[u8] ) -> Result<(), BuildWriteError>

Write all the headers and the payload.

source

pub fn size(&self, payload_size: usize) -> usize

Returns the size of the packet when it is serialized

source§

impl PacketBuilderStep<TcpHeader>

source

pub fn ns(self) -> PacketBuilderStep<TcpHeader>

Set ns flag (ECN-nonce - concealment protection; experimental: see RFC 3540)

source

pub fn fin(self) -> PacketBuilderStep<TcpHeader>

Set fin flag (No more data from sender)

source

pub fn syn(self) -> PacketBuilderStep<TcpHeader>

Set the syn flag (synchronize sequence numbers)

source

pub fn rst(self) -> PacketBuilderStep<TcpHeader>

Sets the rst flag (reset the connection)

source

pub fn psh(self) -> PacketBuilderStep<TcpHeader>

Sets the psh flag (push function)

source

pub fn ack(self, acknowledgment_number: u32) -> PacketBuilderStep<TcpHeader>

Sets the ack flag and the acknowledgment_number.

source

pub fn urg(self, urgent_pointer: u16) -> PacketBuilderStep<TcpHeader>

Set the urg flag & the urgent pointer field.

The urgent pointer points to the sequence number of the octet following the urgent data.

source

pub fn ece(self) -> PacketBuilderStep<TcpHeader>

Sets ece flag (ECN-Echo, RFC 3168)

source

pub fn cwr(self) -> PacketBuilderStep<TcpHeader>

Set cwr flag (Congestion Window Reduced)

This flag is set by the sending host to indicate that it received a TCP segment with the ECE flag set and had responded in congestion control mechanism (added to header by RFC 3168).

source

pub fn options( self, options: &[TcpOptionElement] ) -> Result<PacketBuilderStep<TcpHeader>, TcpOptionWriteError>

Set the tcp options of the header.

source

pub fn options_raw( self, options: &[u8] ) -> Result<PacketBuilderStep<TcpHeader>, TcpOptionWriteError>

Set the tcp options of the header (setting the bytes directly).

source

pub fn write<T: Write + Sized>( self, writer: &mut T, payload: &[u8] ) -> Result<(), BuildWriteError>

Write all the headers and the payload.

source

pub fn size(&self, payload_size: usize) -> usize

Returns the size of the packet when it is serialized

Auto Trait Implementations§

§

impl<LastStep> Freeze for PacketBuilderStep<LastStep>

§

impl<LastStep> RefUnwindSafe for PacketBuilderStep<LastStep>
where LastStep: RefUnwindSafe,

§

impl<LastStep> Send for PacketBuilderStep<LastStep>
where LastStep: Send,

§

impl<LastStep> Sync for PacketBuilderStep<LastStep>
where LastStep: Sync,

§

impl<LastStep> Unpin for PacketBuilderStep<LastStep>
where LastStep: Unpin,

§

impl<LastStep> UnwindSafe for PacketBuilderStep<LastStep>
where LastStep: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.