Skip to content

Commit 6d1d50f

Browse files
committed
✨ Add +short flag to dig command
1 parent 092ddd5 commit 6d1d50f

File tree

6 files changed

+68
-22
lines changed

6 files changed

+68
-22
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "spade-cli"
3-
version = "0.2.3"
3+
version = "0.2.4"
44
description = "You can't dig without a spade! - a super-powered networking tool!"
55
authors = ["Vivaan Verma <hello@vivaanverma.com>"]
66
license = "MIT"

spade/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.2.3"
1+
__version__ = "0.2.4"
22
__app_name__ = "spade"
33

44
__all__ = ("__version__", "__app_name__")

spade/commands/dig.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import textwrap
1+
from pathlib import Path
22
import time
33

44
import dns.rdatatype as RecordType
@@ -101,9 +101,13 @@ def dig(
101101
zone_file: bool = typer.Option(
102102
False, "-z", "--zone-file", help="Output the result in zone file format"
103103
),
104+
short: bool = typer.Option(False, "+short", help="Output only the relevant information"),
104105
) -> None:
105106
"""
106107
Run a DNS lookup.
108+
109+
Resolves DNS records for the given host name by querying the provided DNS
110+
nameserver if one is provided, else using Cloudflare's 1.1.1.1 for speed.
107111
"""
108112

109113
# Perform a DNS query and get the result and the time taken to perform the query.
@@ -115,6 +119,8 @@ def dig(
115119
tcp=tcp,
116120
)
117121

122+
records: list[str] = lookup.rrset.to_text().split("\n")
123+
118124
# If the user requested zone file output, we will output the result in the zone file format.
119125
if zone_file:
120126
rrset: list[str] = lookup.rrset.to_text()
@@ -123,24 +129,28 @@ def dig(
123129
id_: str = str(lookup.response.id)
124130
flags_repr: str = flags.to_text(lookup.response.flags)
125131

126-
output = textwrap.dedent(
127-
f"""
128-
; <<>> Spade {__version__} <<>> {hostname_repr}
129-
;; Got answer:
130-
;; ->>HEADER<<- opcode: {opcode_repr}, status: NOERROR, id: {id_}
131-
;; flags: {flags_repr};
132-
133-
;; ANSWER SECTION:
134-
{rrset}
135-
136-
;; Query time: {time_taken * 1000:.3f} msec
137-
;; SERVER: {lookup.nameserver}:{lookup.port}
138-
;; WHEN: {time.strftime("%H:%M:%S %a %d %b %Y %Z")}
139-
"""
132+
with open(Path(__file__).parent.parent / "templates/dig/zone_file.txt", "r") as zone_file_template:
133+
zone_file_template_content = zone_file_template.read()
134+
135+
output = zone_file_template_content.format(
136+
__version__=__version__,
137+
hostname_repr=hostname_repr,
138+
rrset=rrset,
139+
opcode_repr=opcode_repr,
140+
id_=id_,
141+
flags=flags_repr,
142+
ns=nameserver,
143+
port=nameserver_port,
144+
time_taken=time_taken,
145+
timestamp=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
140146
)
141147
typer.echo(output)
142148

143-
if not zone_file:
149+
elif short:
150+
out = "\n".join(record.split()[-1] for record in records)
151+
typer.echo(out)
152+
153+
else:
144154
styled_record_type: str = typer.style(
145155
lookup.rdtype._name_, fg=typer.colors.BLUE
146156
)
@@ -153,7 +163,7 @@ def dig(
153163

154164
output = f"\nDNS Lookup for {styled_record_type} records for {styled_hostname} through {styled_nameserver}:\n"
155165

156-
records: list[str] = lookup.rrset.to_text().split("\n")
166+
157167
styled_records: list[str] = []
158168

159169
for record in records:

spade/commands/traceroute.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
from icmplib.utils import resolve, unique_identifier
44
from icmplib.sockets import ICMPv4Socket, ICMPv6Socket
55
from icmplib.models import ICMPRequest, TimeExceeded, Hop
6-
from icmplib.exceptions import ICMPLibError
6+
from icmplib.exceptions import ICMPLibError, SocketPermissionError as SPE
77
from rich.text import Text
88
from rich.table import Table
99
from rich.live import Live
1010
from ipwhois.net import Net
1111
from ipwhois.asn import IPASN
1212
from re import match
13+
import typer
14+
15+
from spade.error.traceroute import SocketPermissionError
1316

1417
def traceroute_mine(address, count=1, interval=0.0, timeout=25, first_hop=1,
1518
max_hops=30, id=None, source=None, family=None,
@@ -26,6 +29,10 @@ def traceroute_mine(address, count=1, interval=0.0, timeout=25, first_hop=1,
2629
ttl = first_hop
2730
host_reached = False
2831

32+
try:
33+
_ = _Socket(source)
34+
except SPE:
35+
SocketPermissionError().raise_cli()
2936
with _Socket(source) as sock:
3037
while not host_reached and ttl <= max_hops:
3138
reply = None
@@ -82,7 +89,6 @@ def trace(host):
8289
table.add_column("Maximum RTT (ms)", justify="left")
8390
table.add_column("ASN", justify="left")
8491
table.add_column("ASN Info", justify="left")
85-
ld = 0
8692
with Live(table):
8793
for hop in hops:
8894
if hop is None:
@@ -121,7 +127,6 @@ def trace(host):
121127
asn,
122128
f"https://bgp.tools/as/{asn}"
123129
)
124-
ld = hop.distance
125130

126131
def traceroute(host):
127132
"""

spade/error/traceroute.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import typer
2+
from rich import box
3+
from rich import print
4+
from rich.panel import Panel
5+
6+
7+
class SocketPermissionError(Exception):
8+
def repr(self):
9+
return Panel.fit(
10+
f"\n[red]This user doesn't have permission to create raw sockets on this system[/red]\n[orange]You can retry this command as an administrator or superuser[/orange]\n",
11+
title=f"Missing required permissions",
12+
box=box.SQUARE,
13+
)
14+
15+
def raise_cli(self) -> str:
16+
print()
17+
print(self.repr())
18+
print()
19+
raise typer.Exit(code=1)

spade/templates/dig/zone_file.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; <<>> Spade {__version__} <<>> {hostname_repr}
2+
;; Got answer:
3+
;; ->>HEADER<<- opcode: {opcode_repr}, status: NOERROR, id: {id_}
4+
;; flags: {flags};
5+
6+
;; ANSWER SECTION:
7+
{rrset}
8+
9+
;; Query time: {time_taken} msec
10+
;; SERVER: {ns}:{port}
11+
;; WHEN: {timestamp}
12+
"""

0 commit comments

Comments
 (0)