4

I have crafted a Bash tool that runs on a server. This tool will block certain IP addresses for a certain time range (i.e. from 5 A.M. to 3:30 P.M.).

As of currently, the tool works fine, but I have to input IP addresses to certain websites manually into a text file and have the tool pull the IP address based on the nth line using the "head" and "tail" commands. I don't want to do this as I believe a single ping will be much more lightweight and portable. So if I do a ping for Google:

ping google.com -c 1 -s 16

The output will be:

Ubuntu@yokai:~# ping google.com -c 1 -s 16
PING google.com (173.194.66.138) 16(44) bytes of data.
24 bytes from qo-in-f138.1e100.net (173.194.66.138): icmp_seq=1 ttl=37 time=46.7 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 46.748/46.748/46.748/0.000 ms

And the command I have narrowed this output down with is:

ping google.com -c 1 -s 16 | grep -o '([^ ]*' | tr -d '(44):\n'

Which gives me an output of:

173.19.66.113173.19.66.113ubuntu@yokai

As you can see, there is a duplicate of the same IP address. How can I remove the duplicate with sed so that I can store the single IP address into a variable and run the script as a cronjob, or am I on a better track using tr?

(EDIT)

I already know/knew how to resolve IP address from a host name or domain. That is not what I am asking here. This question is specifically about managing ping output using sed in order to keep the tool I have created more portable as ping comes default with almost any and all linux distros.

(UPDATE) Since some marked this question a duplicate of some other bullshit question that has nothing to do with this one, I will make it clear enough that retards with English comprehension troubles can understand:

How to parse the IP ADDRESS "ONLY" from ping OUTPUT when using ping on a domain name.

This is NOT asking to resolve a domain name and therefore is NOT A DUPLICATE!!!

(LATEST UPDATE) I have, since asking this question, learned proper POSIX regex to do what I needed and I need to make it clear that I was originally asking about the regular expressions for sed that would print a single instance of an IP from ping output. I have since refined my methods and do not use any of the answers here but I thank everyone for their attempts with helping here. I am now using a timer script that I created to configure iptables at certain times to block certain domain name resolutions. Again, thank you to everyone that tried to help.

Yokai
  • 223
  • Editing the question to resolve the possible duplicate. – Yokai Sep 05 '16 at 06:01
  • 1
    Everything about what you are doing gives me a headache. sed operates on each line, whereas ping generates multiple lines of output, of which many contain the string you are looking for. This makes sed not the optimal choice for your problem. If you just want a portable way to resolve a host name, you should look at the link provided by @cutrightjm . If you want to extract IP Adresses from sings you can look here. – Bananguin Sep 05 '16 at 09:59
  • 1
    You clearly state that your goal is getting rid of your manually maintained list of IP addresses. For your approach you provide/use are host names as input. Even your question title says you want to "pull" IP addresses. Everything in the answer(s) you marked as correct can be found in the referenced question, INCLUDING A PING/SED CONSTRUCT. You could have found your answer there; ready for copy/paste. Your question is 100% redundant. This is what we call a duplicate. – Bananguin Sep 06 '16 at 07:32
  • My search, before asking, was: "pull ip address from ping output" and nothing about constructs with sed and ping shown in the suggested answered questions. Either the search results engine is faulty, or it doesn't know how to reference keywords in a search. Regardless, the search suggested posts shown me nothing of use. It is not my fault. Tell it to the maintainers of the site. – Yokai Sep 06 '16 at 10:20
  • If you wish to have proof of what I am telling you, here is a screenshot of my search results: https://www.dropbox.com/s/45asbz1rdcs8zma/proof-of-faulty-results.png?dl=0 – Yokai Sep 06 '16 at 10:30
  • Nothing about this changes the fact that your problem has been stated and solved before on this site. Hence your question is a duplicate. The search engine is probably not perfect. That's why we have mechanisms in place that allow us to reference and link related questions and answers. By ensuring that correct information is widely spread and referenced as often as appropriate we support the search algorithms. The next person looking to "pull IP addresses from ping" will find the correct methods through your question. That's why we mark questions instead of closing or even deleting them. – Bananguin Sep 06 '16 at 11:25
  • @Yokai take a deep breath and calm down. Your tone is way out of line and you are laboring under several wrong assumptions. 1) No moderator was involved in closing your post (mods have that ♦ next to their names). 2) There is nothing wrong with having your post closed as a duplicate. Nobody is accusing you of anything; nobody is saying you did anything wrong. 3) Your question is fine, well formulated and welcome here. It just happens to have already been answered in the linked duplicate and that's why it's closed. – terdon Sep 06 '16 at 12:07
  • Well Bananguin claimed I would have found the answer in the link he provided. I shown the results of my searching terms/phrase and that question he posted never showed in the results. So I would not have found it because I have never seen it called a, "ping/sed construct." I am simply pointing this out. I still don't believe it is a duplicate. I don't care what Bananguin claims. – Yokai Sep 07 '16 at 07:10

3 Answers3

17

ping is for checking whether a host is up or down based on ICMP response, it is never the right tool for only resolving IP address, there are dedicated tools for that.

You should look at dig, host, nslookup -- whatever suites you the best.

Here's a dig output:

% dig +short google.com
123.108.243.57
123.108.243.51
123.108.243.54
123.108.243.48
123.108.243.60
123.108.243.52
123.108.243.56
123.108.243.55
123.108.243.61
123.108.243.58
123.108.243.49
123.108.243.50
123.108.243.59
123.108.243.47
123.108.243.53

As a side note, in Linux, if you want to query by the NSSwitch (Name Service Switch) i.e. /etc/nsswitch, then use the getent command with hosts (or ahosts) database e.g.:

getent hosts google.com

In my computer, i have:

hosts: files mdns4 dns

in /etc/nsswitch.conf, so getent hosts will query in sequence and use gethostbyaddr(3) or gethostbyname(3) based on name and ahosts will use getaddrinfo(3).

In essence, with my configuration, this will first check /etc/hosts, then mDNS and at last DNS.


If you insist on using ping and sed, you can do:

% ping -c1 google.com | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p'
123.108.243.56
heemayl
  • 56,300
  • Very nice! This will avoid all of the pipes I was testing out as well. I completely forgot about dig! Very helpful Sir! – Yokai Sep 05 '16 at 03:16
  • 2
    ping and grep... ping ... | grep -oP 'PING.*?\(\K[^)]+' – Sundeep Sep 05 '16 at 03:23
  • @spasic Same thing, will need PCRE as an addition. – heemayl Sep 05 '16 at 03:24
  • dig, host, and nslookup always use the resolver (i.e. DNS). Other programs may also use the resolver, or they might call gethostbyname(3) or getnameinfo(3), which can be configured to query other sources in addition to DNS (such as /etc/hosts, NIS, etc.). That's of course system-dependent, and to the best of my knowledge there is no standard way to query gethostbyname(3) short of writing a program. However most implementations of ping(8) do call gethostbyname(3), and that's why people use ping(8) to resolve addresses. They aren't completely in the wrong. :) – Satō Katsura Sep 05 '16 at 05:38
  • @SatoKatsura getent hosts? – heemayl Sep 05 '16 at 05:41
  • Only if you specifically want to query /etc/hosts. Most of the time you have no idea (and don't care) whether your programs will query /etc/hosts or DNS first, whether they will query NIS etc. – Satō Katsura Sep 05 '16 at 05:44
  • @SatoKatsura getent hosts (and all others) queries according to nsswitch, and passes each argument to gethostby..... – heemayl Sep 05 '16 at 05:58
  • ... On Linux. Not on *BSD or Solaris. – Satō Katsura Sep 05 '16 at 06:00
  • @SatoKatsura I have incorporated the details. – heemayl Sep 05 '16 at 06:44
6

Browsing Google I found a link to another unix.SE post that mentions getent - I didn't even know this program existed.

You can use getent like dig to resolve an IP to a hostname - and my system had getent installed by default, but not dig. If you want ipv6 hosts, change ahostsv4 to ahostsv6.

getent ahostsv4 google.com | awk '{print $1}' | head -1

I added this answer because I'm bad at regexes / sed and wouldn't have been able to come up with @heemayl's answer.

cutrightjm
  • 5,290
3

One thing to note is that, as you see in @heemayl's dig output, some sites may have more than one IP address. You'll likely need a DNS lookup to get them all, as ping will just use the first address it gets. Same for anything else that mainly wants to connect, and not specifically list the addresses.

(Also, in the case of something like google, you'll get different IP addresses depending on where you are based. Might not be a problem here, but good to note.)

Another thing, about the command you used. This: tr -d '(44):\n' removes all copies of the characters (, 4, ), : and \n from the input. tr always only looks at single characters, not strings. Looking at the output you got, you'll see that a 4 has gone missing from the middle of the IP address. Use some other tool like sed to work with strings.

Just for the sake of showing different colours for the bike shed, here's another simple one, with GNU grep:

$ ping google.com -c1 | head -1 | grep -Eo '[0-9.]{4,}'
172.217.22.174
ilkkachu
  • 138,973
  • I am already aware that some domain names give out more than one IP address. That isn't an issue. The command I gave was an example of my researching on my own. It has since been corrected in my tool. There is no reason to point out the obvious. – Yokai Sep 06 '16 at 05:20
  • I am also aware that the (44) that was printed to standard output was removed. That was intentional. There was no 4 removed from my ping output from an IP address as the IP addresses I connect to do not have a 4 in them. The IP is 173.19.66.113. This doesn't have a 4 in it. – Yokai Sep 06 '16 at 05:25
  • @Yokai, Your stated purpose was to block certain sites based on their IP addresses. In that case one wants to make sure to get all of the IP addresses, since otherwise they'll only some connections; a simple reload might get another address and connect. That makes ping hard to use for name resolving in this case. This may be obvious to you, but it's not obvious from the question as written. Any future readers might not think about it immediately, so it's worth pointing out. – ilkkachu Sep 06 '16 at 06:57
  • @Yokai, also, in your example, the address does have a 4 in it, and it's duly removed by tr. The output from ping starts PING google.com (173.194.66.138) 16(44) bytes of data. Of course in your other snippet, the address ends in .113, not .138, so clearly a different address was picked this time. While the addresses of any given hostname don't need to have any relation with each other, I think it's far more likely for the addresses of google.com to only differ in the last octet, than for them to differ in the second octet (with the third remaining the same, even). – ilkkachu Sep 06 '16 at 07:07
  • @Yokai, also: the address and matching DNS name in your example: 173.194.66.138 -> qo-in-f138.1e100.net, the same with .113: 173.194.66.113 -> qo-in-f113.1e100.net. The same without the 4 is in a different domain entirely: 173.19.66.113 -> 173-19-66-113.client.mchsi.com. (that looks like a name for a dynamically assigned DHCP address.) Even if your addresses don't have any fours in them, it's not very robust to assume they never will, since the point of name resolving is that you don't need to care if the addresses change. – ilkkachu Sep 06 '16 at 07:13
  • Now that I look back at the original ping output, you are correct. There was a 4 removed. That would be my mistake. – Yokai Sep 06 '16 at 10:16