ステルス・スキャン　あるいは　カリグラム的プログラム

前回のプログラムでカリグラム的なことをしてみました。

https://qiita.com/mekamaru/items/6dd840f7f5a6b11fce79

ステルス・スキャンなので「隠」の一字です。

```rust
const TO:u64=5000;const M:[&str;4]=["open","closed","timeout","unknown"];use pnet::{
ipnetwork::IpNetwork as IN,packet::{ip::IpNextHeaderProtocols::Tcp, ipv4::Ipv4Packet
as I4P,  Packet,  tcp :: { ipv4_checksum  as  ic,           MutableTcpPacket as MTP,
TcpFlags:: {ACK, RST, SYN},  TcpOption as TOP,             TcpPacket as TP},ethernet
:: {EtherTypes as ET,  EthernetPacket as EP}},                  datalink::{Channel::
Ethernet as E,NetworkInterface as NI, {channel                 as chn, interfaces as
ifcs }}, transport:: { transport_channel as tc,               TransportChannelType::
Layer4 as L4,TransportProtocol::Ipv4}};use rand              ::Rng; use std::{net::{
IpAddr  as     IA,     Ipv4Addr as I4A},str::               FromStr,  sync::mpsc:: {
channel as ch,          RecvError   as   MRE,             RecvTimeoutError as MRTE},
thread::{                sleep,spawn},time          ::Duration as D};const SA:u8=SYN
+ACK;const                RA:u8=RST+ACK;fn       main(){if let Err(e)=run(){eprintln
!(                        "[Error] {:?}",e)  }}fn run()->Result<(),ME>{let args:Vec<
String                    >=std::env::args()   .collect();if args.len()<2{return Ok(
eprintln                  !(                    "Usage: {} interface ip:port",args[0
]))                      ;}if   args.len()<3      {return         Err(ME::TFAE);}let
ifcn=      &args         [1];let tgt:&str=&            args[2       ];Ok(pr(tgt,prc(
ifcn.to_string          (),tgt    )?))}fn pr         (tgt:&str       ,ff:u8){println
!("[Result]");          println     !("{}: {}"       ,tgt,M[          match ff{SA=>0
,RA=>1,0=>2,_          =>3,}])       ;}fn prc        (ifcn:          String,tgt:&str
)->Result<u8,         ME>{let(ri      ,rp)=sip       (tgt)?           ;let r=ifcs().
into_iter().          find(|ifc         |ifc.        name==       ifcn);if r.is_none
(){return Err        (ME::UIE);          }let       ifc=r          .unwrap();println
!(                  "Interface: {}"      ,ifc.name  );let         mut li:Option<I4A>
=None;for ip        in&ifc.ips{if         let IN:: V4(v4         )=ip{li=Some(v4.ip(
));break;}}        if li.is_none(         ){return Err         (ME::LIE);}let li=li.
unwrap();let      mut rng=rand::          thread_rng(        );let lp=rng.gen_range(
32768..=60999    );let ff=SYN; let        seq:u32=        rand::random();let ack:u32
=0;    println    !("Local:  {}:{}",li   ,lp);           println!("Remote: {}:{}",ri
,rp     );s_r     (ifc,lp,rp,li,ri,ff,seq,ack)             }fn s_r(ifc:NI,lp:u16,rp:
u16     ,li:I4A    ,ri:I4A,ff:u8,seq:u32,ack                   :u32,)->Result<u8,ME>
{let     (mut       tx,_)=tc(4096,L4(                               Ipv4(Tcp)))?;let
mut      bb:[u8       ;24]=[0;24];let                                p=th(&mut bb,lp
,rp       ,li,ri       ,ff,seq,ack)?                   ;let(          t,r)=ch(); let
h =       spawn (       move||{t.send             (match recv          (ifc,lp,rp,li
,ri       ){Err(e)       =>{eprintln          !("[Error] {:?}"         ,e);0u8}Ok(ff
)=>       ff, } ).       unwrap();});   sleep(D::from_millis           (100));   tx.
send_to    (p,IA::         V4(ri))?; pth( "[Sent]", ff, seq,           ack,1000);Ok(
match                        r.recv_timeout             (D::             from_millis
(TO                          )){Ok(f)=>              {h.join           ().unwrap();f
}_=>                         0,})}                   fn th(           bb:&mut[u8],lp
:u16                         ,rp                    :u16,li           :I4A,ri:I4A,ff
:u8                        ,seq:u32              ,ack:u32,)          ->Result<MTP,ME
>{let      pkt   = MTP::new(bb); if           pkt.is_none(           ){return Err(ME
::        MTPE);}let mut pkt=pkt.unwrap();pkt.set_flags(ff          );pkt.set_source
(lp)      ;pkt.set_destination(rp);pkt.set_window(1000);         pkt.set_data_offset
(6        ) ; pkt . set_acknowledgement( ack );               pkt.set_sequence(seq);
pkt        .set_options( &[TOP::mss(1460)                        ]);pkt.set_checksum
(ic       (&pkt.to_immutable(),&li,&ri))                        ;Ok(pkt)}fn recv(ifc
:NI      ,lp:u16,rp:u16,li:I4A,ri:I4A                           )->Result<u8,ME>{let
mut      ff=0u8;if let E(_,mut rx)=                        chn(&ifc,Default::default
()       )? {loop{let bytes=rx.next                    ()?;let frame=EP::new(bytes);
if       frame.is_none(){continue;}let frame = frame.unwrap();if frame.get_ethertype
()       !=ET::Ipv4{continue;} let ipv4=I4P::new(frame.payload()); if ipv4.is_none()
{        continue;} let ipv4=ipv4.unwrap(); if ipv4.get_source()!=ri ||         ipv4
.        get_destination()!=li{continue;}if ipv4.get_next_level_protocol           (
)        !=Tcp{continue;}let tcp=TP ::new(ipv4              .payload()
);       if tcp.is_none(){continue  ;}let tcp               =tcp.unwrap
()       ;if tcp.get_source()!=rp  ||tcp.                get_destination
(        )!=lp{continue;}ff=tcp.      get_flags           ();let seq=tcp
.        get_sequence();let ack=tcp    .                get_acknowledgement
(        );let win=tcp.   get_window    ();pth(            "[Received]",ff,
seq      ,ack,win);break   ; }}Ok(ff     )}fn pth           (tag:&str,ff:u8,seq    :
u32      ,ack:u32,win:u16     ){          println!("{}",  tag);println!("Flags:  {}"
,        conv(ff));println      !(        "Seq No: {}"             ,seq);    println
!        ("Ack No: {}"          ,ack)       ;println!(             "Window: {}",win)
;        }const F:[&str         ;8]=[       "FIN","SYN","RST",     "PSH","ACK","URG"
,        "ECE","CWR"];fn         conv(       ff:u8)->String{let     mut r=vec![];let
         mut a=0;while a         <8{let       b=2u32.pow(a as          u32);if(ff as
         u32)&b!=0{r.push         (F[a]         );}a+=1;}r.join         (",")}fn sip
         (s:&str)->Result         <(I4A          ,u16),ME>{let           a:Vec<&str>
         =s.split(':').           collect             ();if               a.len()!=2
{        return Err(ME::TE        );}if                                    let Ok(ip
)        =I4A::from_str(a[0        ]){if                                 let Ok(port
)=       a[1].parse(){return      Ok((ip,port                              ));}}Err(
ME::     TE)}#[derive(thiserror  ::Error,Debug                            )]enum ME{
#[      error("IOE")]IOE(#[from]std::io::Error),                    #[error("MTPE")]
MTPE,#[error("TFAE")]TFAE,#[error("TE")]TE,#[error("UIE")]UIE,#[error("LIE")]LIE, #[
error("TOE")]TOE(#[from]MRTE),#[error("RE")]RE(#[from]MRE),}/*by mekamaru(@bunji2)*/
```

内容はほぼ変えず、使うモジュール名の短縮化、変数名の短縮化などを行いました。

Tシャツにするとこんな感じ。。。

![T.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960096/e7bc43a6-6d63-e1c5-f8e0-5fb437edf027.png)

厳しいか。。。