Intro
While I was on vacation someone replaced a certificate which had expired on the F5 Big-IP load balancer. Maybe they were not quite as careful as I would like to hope I would have been. In any case, shortly afterwards our SiteScope monitoring reported there was an untrusted server certificate chain. It took me quite some digging to get to the bottom of it.
The details
Well, the web site came up just fine in my browser. I checked it with SSLlabs and its grade was capped at B because of problems with the server certificate chain. I also independently confirmed usnig openssl that no intermediate certificate was being presented by this virtual server. To see what that looks like with an exampkle of this problem knidly privided by badssl.com, do:
CONNECTED(00000003)
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=27:certificate not trusted
verify return:1
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
i:/C=US/ST=California/L=San Francisco/O=BadSSL/CN=BadSSL Intermediate Certificate Authority
-----BEGIN CERTIFICATE-----
MIIE8DCCAtigAwIBAgIJAM28Wkrsl2exMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
...
HJKvc9OYjJD0ZuvZw9gBrY7qKyBX8g+sglEGFNhruH8/OhqrV8pBXX/EWY0fUZTh
iywmc6GTT7X94Ze2F7iB45jh7WQ=
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
issuer=/C=US/ST=California/L=San Francisco/O=BadSSL/CN=BadSSL Intermediate Certificate Authority
...
Verify return code: 21 (unable to verify the first certificate)
CONNECTED(00000003)
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=27:certificate not trusted
verify return:1
depth=0 /C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
i:/C=US/ST=California/L=San Francisco/O=BadSSL/CN=BadSSL Intermediate Certificate Authority
-----BEGIN CERTIFICATE-----
MIIE8DCCAtigAwIBAgIJAM28Wkrsl2exMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
...
HJKvc9OYjJD0ZuvZw9gBrY7qKyBX8g+sglEGFNhruH8/OhqrV8pBXX/EWY0fUZTh
iywmc6GTT7X94Ze2F7iB45jh7WQ=
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=San Francisco/O=BadSSL Fallback. Unknown subdomain or no SNI./CN=badssl-fallback-unknown-subdomain-or-no-sni
issuer=/C=US/ST=California/L=San Francisco/O=BadSSL/CN=BadSSL Intermediate Certificate Authority
...
Verify return code: 21 (unable to verify the first certificate)
So you get that message about benig unable to verify the first certificate.
Here’s the weird thing, the certificate in question was issued by Globalsign, and we have used them for years so we had the intermediate certificate configured already in the SSL client profile. The so-called chain certificate was GlobalsignIntermediate. But it wasn’t being presented. What the heck? Then I checked someone else’s Globalsign certificate and found the same issue.
Then I began to get suspicious about the certificate. I checked the issuer more carefully and found that it wasn’t from the intermediate we had been using all these past years. Globalsign changed their intermediate certificate! The new one dates frmo November 2018 and expires in 2028.
And, to compound matters, F5 “helpfully” does not complain and simply does not send the wrong intermediate certificate we had specified in the SSL client profile. It just sends no intermediate certificate at all to accompany the server certificate.
Conclusion
The case of the missing intermediate certificate was resolved. It is not the end of the world to miss an intermediate certificate, but on the other hand it is not professional either. Sooner or later it will get you into trouble.
Intro
I can not find a link on the Internet for this, yet I think some admins would appreciate a relatively simple test to know is this a web site which requires a client certificate to work? The errors generated in a browser may be very generic in these situations. I see many ways to offer help, from a recipe to a tool to some pointers. I’m not yet sure how I want to proceed!
why would a site require a client CERT? Most likely as a form of client authentication.
Pointers for the DIY crowd Badssl.com plus access to a linux command line – such as using a Raspberry Pi I so often write about – will do it for you guys.
The Client Certificate section of badssl.com has most of what you need. The page is getting big, look for this:
So as a big timesaver badssl.com has created a client certificate for you which you can use to test with. Download it as follows.
Go to your linux prompt and do something like this:
$ wget https://badssl.com/certs/badssl.com‐client.pem
* About to connect() to client.badssl.com port 443 (#0)
* Trying 104.154.89.105... connected
* Connected to client.badssl.com (104.154.89.105) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* skipping SSL peer certificate verification
* NSS: client certificate from file
* subject: CN=BadSSL Client Certificate,O=BadSSL,L=San Francisco,ST=California,C=US
* start date: Nov 16 05:36:33 2017 GMT
* expire date: Nov 16 05:36:33 2019 GMT
* common name: BadSSL Client Certificate
* issuer: CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.badssl.com,O=Lucas Garron,L=Walnut Creek,ST=California,C=US
* start date: Mar 18 00:00:00 2017 GMT
* expire date: Mar 25 12:00:00 2020 GMT
* common name: *.badssl.com
* issuer: CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: client.badssl.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.10.3 (Ubuntu)
Server: nginx/1.10.3 (Ubuntu)
< Date: Thu, 20 Jun 2019 17:59:08 GMT
Date: Thu, 20 Jun 2019 17:59:08 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 662
Content-Length: 662
< Last-Modified: Wed, 12 Jun 2019 15:43:39 GMT
Last-Modified: Wed, 12 Jun 2019 15:43:39 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "5d011dab-296"
ETag: "5d011dab-296"
< Cache-Control: no-store
Cache-Control: no-store
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
<style>body { background: green; }</style>
* About to connect() to client.badssl.com port 443 (#0)
* Trying 104.154.89.105... connected
* Connected to client.badssl.com (104.154.89.105) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* skipping SSL peer certificate verification
* NSS: client certificate from file
* subject: CN=BadSSL Client Certificate,O=BadSSL,L=San Francisco,ST=California,C=US
* start date: Nov 16 05:36:33 2017 GMT
* expire date: Nov 16 05:36:33 2019 GMT
* common name: BadSSL Client Certificate
* issuer: CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.badssl.com,O=Lucas Garron,L=Walnut Creek,ST=California,C=US
* start date: Mar 18 00:00:00 2017 GMT
* expire date: Mar 25 12:00:00 2020 GMT
* common name: *.badssl.com
* issuer: CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: client.badssl.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.10.3 (Ubuntu)
Server: nginx/1.10.3 (Ubuntu)
< Date: Thu, 20 Jun 2019 17:59:08 GMT
Date: Thu, 20 Jun 2019 17:59:08 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 662
Content-Length: 662
< Last-Modified: Wed, 12 Jun 2019 15:43:39 GMT
Last-Modified: Wed, 12 Jun 2019 15:43:39 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "5d011dab-296"
ETag: "5d011dab-296"
< Cache-Control: no-store
Cache-Control: no-store
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
<style>body { background: green; }</style>
client.
badssl.com
* Connection #0 to host client.badssl.com left intact
* Closing connection #0
* Connection #0 to host client.badssl.com left intact
* Closing connection #0
No more 400 error status – that looks like success to me. Note that we had to provide the password for our client CERT, which they kindly provided as badssl.com
Here’s an example of a real site which requires client CERTs:
* About to connect() to jp.nissan.biz port 443 (#0)
* Trying 150.63.252.1... connected
* Connected to jp.nissan.biz (150.63.252.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* skipping SSL peer certificate verification
* NSS: client certificate from file
* subject: CN=BadSSL Client Certificate,O=BadSSL,L=San Francisco,ST=California,C=US
* start date: Nov 16 05:36:33 2017 GMT
* expire date: Nov 16 05:36:33 2019 GMT
* common name: BadSSL Client Certificate
* issuer: CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
* NSS error -12227
* Closing connection #0
* SSL connect error
curl: (35) SSL connect error
* About to connect() to jp.nissan.biz port 443 (#0)
* Trying 150.63.252.1... connected
* Connected to jp.nissan.biz (150.63.252.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* skipping SSL peer certificate verification
* NSS: client certificate from file
* subject: CN=BadSSL Client Certificate,O=BadSSL,L=San Francisco,ST=California,C=US
* start date: Nov 16 05:36:33 2017 GMT
* expire date: Nov 16 05:36:33 2019 GMT
* common name: BadSSL Client Certificate
* issuer: CN=BadSSL Client Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
* NSS error -12227
* Closing connection #0
* SSL connect error
curl: (35) SSL connect error
OK, so you get an error, but that’s to be expected because our certificate is not one it will accept.
The point is that if you don’t send it a certificate at all, you get a different error:
$ curl ‐v ‐i ‐k https://jp.nissan.biz/
* About to connect() to client.badssl.com port 443 (#0)
* Trying 104.154.89.105... connected
* Connected to client.badssl.com (104.154.89.105) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* Unable to load client key -8025.
* NSS error -8025
* Closing connection #0
curl: (58) Unable to load client key -8025.
Chrome gives a fairly intelligible error
Possibly to be continued…
Conclusion
We have given a recipe for testing form a linux command line if a web site requires a client certificate or not. thus it could be turned into a program
Intro
I’m trying out the system-supplied postfix on a SLES system. i had been using sendmail but there doesn’t seem to be any development on that software.
Some commands I needed right away
Well, right away I had thousands of queued messages so I needed a way to make sense of what was happening.
For these commands to make sense you need to know that I am running a second postfix configuraiton out of /etc/postfixEXT.
Display the queue
postqueue -c /etc/postfixEXT -p
postqueue -c /etc/postfixEXT -p
Force delivery from the queue
postqueue -c /etc/postfixEXT -f
postqueue -c /etc/postfixEXT -f
List one email in detail
postcat -vq -c /etc/postfixEXT QUEUEID
postcat -vq -c /etc/postfixEXT QUEUEID
Delete one email
postsuper -c /etc/postfixEXT -d QUEUEID
postsuper -c /etc/postfixEXT -d QUEUEID
Put mail on hold
postsuper -c /etc/postfixEXT -h ALL|QUEUEID
postsuper -c /etc/postfixEXT -h ALL|QUEUEID
Release mail form hold
postsuper -c /etc/postfixEXT -H ALL|QUEUEID
postsuper -c /etc/postfixEXT -H ALL|QUEUEID
How to force delivery of a single message
This command is not documented anywhere – because it doesn’t exist so you have to get creative. If you have the luxury of halting all email for a few seconds simply do this:
Display the queue to find the queue ID of the email you want to force delivery of
postqueue -c /etc/postfixEXT -p
postqueue -c /etc/postfixEXT -p
Put all mail on hold
postsuper -c /etc/postfixEXT -h ALL
postsuper -c /etc/postfixEXT -h ALL
Now release the hold on that one email
postsuper -c /etc/postfixEXT -H QUEUEID
postsuper -c /etc/postfixEXT -H QUEUEID
QUEUEID is, of course, the queue id .e.g., F2A1A27891E, of the email in question.
Look for what happened
Check your mail log’s last lines in /var/log/mail
Revert back to normal running
postsuper -c /etc/postfixEXT -H ALL
postsuper -c /etc/postfixEXT -H ALL
Since mail is store-and-forward and not real time, you can do these steps, quickly, even on a production system and no one will be the wiser if you are pretty quick. Probably takes two minutes even for a slow typer.
How to run multiple listeners
I didn’t want to disturb the system-installed postfix too much. I would let it “have” the loopback address, 127.0.0.1, leaving me the other IPs for my relay config to listen on. I added these lines to /etc/postfix/main.cf
service postfix start starts up the local postfix plus my relay. Grep the process table for either master or postfix to see. However, to be honest, service postfix stop does not kill all processes. So I always end up killing one of the master processes by hand. Update: postmulti -p stop does the trick to kill all. There is also a status or start option instead of stop.
Sendmail to Postfix migration tips
This could be a separate post but I am too lazy to do that.
What happens to the access file? I kept the name of the file access but just list all the IPs, one per line, without any further arguments, to permit just those IPs relay access. In my main.cf I have a line like this to tie it together:
mynetworks = /etc/postfixEXT/access
mynetworks = /etc/postfixEXT/access
Note that there is no hashed or .db version of this file any longer, unlike in the sendmail case.
I haven’t run this in two years. I just revived my scripts today, resuscitated an old Raspberry Pi, and voila, it’s pretty much good to go. When I moved to my new server in 2020 some of the scripts got mangled. I’m trying to fix those. For the record, I use the continuousaudio.sh script + ffmpegwireless6.sh mentioned below. That gives me a live audio stream on YouTube with a solid gray video. I’m researching further enhancements and will post those if I ever manage to pull them off.
What I would like to do is to have it interpret and respond to a couple audio commands as in “start recording” and “stop recording”. Now whether or not I can pull that off is an entirely different story. But you’ll never know if you don’t try…
Intro
I’ve been looking at this off and on for awhile now. I finally made a breakthrough this week and started to generate some decent live streams on my YouTube channel, after a lot of misfires.
Note this is applicable for Raspbian Stretch Lite on a Raspberry Pi 3. However, I firmly believe it will work just the same for regular Raspbian Stretch.
There’s a lot of wrong, misleading or outdated information out there on the Internet. Hopefully this will help others to avoid wasting as much time as I had to do.
This project was prompted by my desire to make a more generalized fishcam! Described in this post, my original fishcam implementation – and I realized this form the get-go – has very limited applicability because very few people are in a position to have their own AWS server. And if you don’t know what you’re doing, please don’t run your own server – the security exposure is too great.
So I eventually realized that maybe I could generalize what I had done – essentially remove the dependency on the AWS server – by utilizing Youtube Live Streaming. And, I believe I was right. It’s still a work in progress however.
The command – ffmpeg
I was playing with ffmpeg. The version I am playing with now comes with Raspbian – no need to compile like in the bad old days. ffmpeg -version shows the version to be 3.2.12. I get the impression that its capabilities are version-dependent, so that’s why this information is particularly relevant in this case.
The details
In some of my early attempts I was getting a lot of this (looking at YouTube Live Dashboard)
Another attempt
Video works, audio like driving in a car with the windows down. For the record, the command was this:
It is not so pretty to use that hardware address for the Logitech webcam device. Where do you see that hardware address? Either a lsusb or a ls /dev/snd/by-id shows addresses of sound devices. I found a simpler substitute:
With this audio's, not too bad, video's a bit choppy. Google reports the stream quality as OK, check resolution.
So I fix the bandwidth (which was a typo in the above, but one with an interesting result). I set video bandwidth to -b:v 1200k. Now the video is OK once again, but the audio is choppy again! Weird. bandwidth is about 1100 kbps.
This version had OK video and OK audio
But I keep getting inconsistent results! Sometimes a setting will work, and then I come back to it and it doesn’t. Weird.
Part of the problem is that I have no idea what I’m doing and I didn’t know when i was watching a livestream vs a recorded (on-demand) one! I have since learned to look for the little red Live button. A picture is worth 10^3 words in this case.
[Pic no longer available – try the thousand words instead!]
Observed used bandwidth is about 1450 kbits/sec. But still lots of dropped packets. Here is what ffmpeg reports. I’m not sure yet what most of it means:
That is working great – showing the video as before but now with a silent audio track.
Increase Video Quality
Here I’ve increased video quality a tad by requesting more fps (10) and making qscale 0 (which means highest quality). https://www.youtube.com/watch?v=5Aall8w4Y3E
What is observed to happen is that ffmpeg actually chooses 15 fps rather than 30. I’ve read it decides what it is able to do, so maybe that’s the highest fps it can deliver. Video is pretty smooth (See my Livestream link in references if I happen to have it running. Otherwise I will create a video link.) No drops are recorded, but the sound, though not terrible, has some pops. Bandwidth used is about 1900 kbps. So this is definitely my best effort yet. YouTube complains about the unsupported video size of 640×480, but it permits it and I don’t think it’s a real problem.
Reducing bandwidth
This one is pretty good overall. I have no idea why lowering the audio bandwidth might help. It’s counter intuitive. But video motion is not bad – just a tad blurred. I guess q=23. Audio has good patches and not-as good patches. Not as good spots are staticky, not washboard bad. Total bandwidth used is about 611 kbps. So a great compromise. Why does raising the video bandwidth lower the audio quality? I have no idea… The settings below worked for maybe 20 minutes, then YouTube said this Video is unavailable. I at least found out something about that. That shows a problem with the player, not (for once) your stream. so since I’m only concentrating on the stream, that’s good news. So actually it delivered good sound for three hours straight with a few staticky spots.
The audio is creepily sensitive, easily picking up conversations in adjacent rooms.
But then I monkeyed around with the settings, got the washboard sound, came back to this one – a known good – and got washboard audio! What the heck? Why isn’t it consistent?? No idea… Maybe it’s the player that gets messed up?? Now I’m running it again and it’s OK.
Bandwidth talk
It’s important to talk about bandwidth if you haven’t given this any real thought. You have to have a halfway decent broadband connection for this to work, you see? If you have a mid-speed cable modem or DSL, you have much lower upload than download speeds, and you may not be able to pull off a reliable 1.5 mbps upload. For those lucky enough to have Verizon FIOS this is a non-issue. But for instance in the high school where I volunteer they have throttled the guest WiFi network to such an extent that achieving this modest 1.5 mbps is going to present a real challenge. If you rely on a phone’s hotspot you will also probably be unable to get such a speed. So I may look at more ways to reduce the bandwidth required in the future.
And between YouTube and your ISP, it just seems the whole thing about live video broadcasting seems, well, delicate. Stream Health varies between oK, to Excellent to not receiving – all during the same streaming session! It often takes five minutes or so for the stream to appear to be working.
Comparing two webcams
Someone picked up a really cheap DI Chatcam at Microcenter in Paterson. I think that’s Digital Innovations Chatcam. It’s cute. It has a big clip on the end and shines white LEDs when it’s on. I think it was about $12. With the exact same ffmpeg settings (with audio suppressed), the quality was not nearly as good as with the Logitech webcam. Here’s a link to the YouTube video made with the chatcam: https://www.youtube.com/watch?v=OI2IRV1i__k. Note that it has a ministereo plug for audio. I didn;’t even plug it in now that I know how to suppress audio!
I need to re-run this test now that I know how to increase the video quality.
A breakthrough: publishing an audio-only stream to YouTube
Besides covering your lens with tape, what’s a software way to blacken the video and concentrate on producing the best audio I wondered?
The above gives me good audio, and a sold gray background. I love it – for recording band practice or whatever. The breakthrough is that we can avoid wasting cpu cycles on processing input video but just use a color. Thanks Stackoverflow for the tip. Used bandwidth is about 150 kbs – basically nothing! YouTube Dsahboard complains:
OK Video output low
The stream's current bitrate (138.00 Kbps) is lower than the recommended bitrate.
We recommend that you use a stream bitrate of 2500 Kbps.
OK Video output low
The stream's current bitrate (138.00 Kbps) is lower than the recommended bitrate.
We recommend that you use a stream bitrate of 2500 Kbps.
But of course that is bogus because that assumes we are trying to put out a rich 1280×720 video, which we are not.
Then eventually YouTube has this complaint:
Bad Bad video settings
Please use a keyframe frequency of four seconds or less. Currently, keyframes are not being sent often enough, which will cause buffering.
The current keyframe frequency is 8.5 seconds. Note that ingestion errors can cause incorrect GOP (group of pictures) sizes.
Bad Bad video settings
Please use a keyframe frequency of four seconds or less. Currently, keyframes are not being sent often enough, which will cause buffering.
The current keyframe frequency is 8.5 seconds. Note that ingestion errors can cause incorrect GOP (group of pictures) sizes.
Yet the stream does not seem to suffer in any noticeable way from this problem.
For good measure, we add a few extra arguments allow us to remove the keyframes warning. We need to use the -g parameter (group of pictures) at about twice our frame rate, plus, maybe, a no-scenecut argument. Here’s that version.
Actual fps is 25, quality is 26 and bitrate is 145 kbps. But audio quality is good. I hear white noise in the background, but hey, this isn’t exactly professional equipment we’re working with. But this is a great solution for an audio-only recording that goes straight out to YouTube. stability is also good.
The load average is high – 3.6 (use top to watch it), almost all of it taken by ffmpeg. So it appears ffmpeg is really working it to produce this audio stream. That makes me suspect it just gets overwhelmed when it’s an audio + video stream? Because I never did find setting swhich produced good quality for both…
Switch to Wifi and Yet another problem surfaces
It seems that with this livestreaming project everything that should just work doesn’t! I had been doing all my testing used wired Ethernet connection and WiFi disabled. anticipating a portable solution, I tried it using WiFi and no Ethernet cable. And washboard audio reappeared. quite often ffmpeg hangs as well. I tried a zillion experiments and now my revelation is that essentially, though we tried to minimize and trivialize video, we were probably still overwhelming the CPU. So I reasoned that these actions will make the load easier on the CPU, without compromising the audio quality:
– reduce frame per second dramatically
– reduce key frames
– reduce video size
And…yes, these things in combination really did help and permit me to run over WiFi now. This version, put inside a script I call ffmpegwireless6.sh, looks like this:
It doesn’t start consistently, however, but if you run it enough times it’ll go. So, to provide reliability I also scripted around these deficiencies: I decided to just keep trying to start up ffmpegwireless.sh until I jhave evidence it’s working. I call that script masterwireless.sh:
#!/bin/sh
# DrJ 5/2019
LOG="ff.log"`date +%m-%d-%y:%H:%M`
while /bin/true; do
nohup ./ffmpegwireless6.sh$LOG 2>&1 &
sleep 7
# want s.th like
#Frame= 84 fps= 11 q=16.0 size= 43kB time=00:00:07.50 bitrate= 47.1kbits/s dup=0 drop=431 speed=0.991x
#Frame= 84 fps= 11 q=16.0 size= 43kB time=00:00:07.50 bitrate= 47.1kbits/s dup=0 drop=431 speed= 1x
FFOUT=`tail -1 $LOG`
echo "last line is $FFOUT"
KB=`echo $FFOUT|awk '{print $(NF-4)}'`
echo "orig KB: $KB"
KB=`echo $FFOUT|awk '{print $(NF-5)" "$(NF-4)}'|sed 's/kbits.*//'|awk '{print $NF}'`
date
echo "KB is: $KB"
if [ $KB -gt 129 2>/dev/null ]; then
# let our master process exit - we've got a good audio stream
echo "Exiting at *** "`date`
exit
else
# didn't work out: restart and try again
echo "*** Restarting ffmpeg at *** "`date`
pkill -9 -f 'ffmpeg '
fi
done
And…it works great! Very briefly what it does is t that it calls ffmpegwireless6.sh and backgrounds it, then tests its output. It gives it a few seconds to get going, then kills it unless observed streaming bandwidth is a healthy 135 kbps or so (essentially the video takes almost no bandwidth in ffmpegwireless6.sh.)
Putting it all together – livestreaming audio stream to YouTube automatically upon boot up
So I want to drag this thing to a performance and have a confederate with minimal technical know-how start it up. So basically I want it to start livestreaming when the RasPi is powered up. To do that I made this crontab entry (using crontab -e):
It takes a few minutes to get going, but it’s been extremely reliable. It’s started a stream successfully more than 10 times out of 10, at least when I was using my home WiFi connection. When I switched to my phone’s Hotspot, I had one error out of five attempts. The one bad stream just would not start according to Youtube, although per the stats from the log files showed the stream reached the usual good bandwidth. So I don’t know…
And once the stream starts, it is running uninterrupted for hours, anywhere from three to six hours.
Eventually I want to write an API program to automatically check the stream. But before then I may just introduce a refined script which checks the output and restarts ffmpeg when it has ended.
For the record, a typical ff.log file looks like this:
frame= 43 fps= 43 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=164 speed= 0x ed= 0x
orig KB: dup=0
Tue 7 May 12:32:08 BST 2019
KB is: dup=0
*** Restarting ffmpeg at *** Tue 7 May 12:32:08 BST 2019
frame= 213 fps= 35 q=8.0 size= 47kB time=00:01:40.91 bitrate= 3.8kbits/s dup=0 drop=847 speed=16.7x
orig KB: 3.8kbits/s
Tue 7 May 12:38:53 BST 2019
KB is: 3
*** Restarting ffmpeg at *** Tue 7 May 12:38:53 BST 2019
illed= 86 fps= 14 q=8.0 size= 104kB time=00:00:06.21 bitrate= 136.7kbits/s dup=0 drop=336 speed=1.03x
orig KB: 136.7kbits/s
Tue 7 May 12:39:00 BST 2019
KB is: 136
Exiting at *** Tue 7 May 12:39:00 BST 2019
frame= 43 fps= 43 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=164 speed= 0x ed= 0x
orig KB: dup=0
Tue 7 May 12:32:08 BST 2019
KB is: dup=0
*** Restarting ffmpeg at *** Tue 7 May 12:32:08 BST 2019
frame= 213 fps= 35 q=8.0 size= 47kB time=00:01:40.91 bitrate= 3.8kbits/s dup=0 drop=847 speed=16.7x
orig KB: 3.8kbits/s
Tue 7 May 12:38:53 BST 2019
KB is: 3
*** Restarting ffmpeg at *** Tue 7 May 12:38:53 BST 2019
illed= 86 fps= 14 q=8.0 size= 104kB time=00:00:06.21 bitrate= 136.7kbits/s dup=0 drop=336 speed=1.03x
orig KB: 136.7kbits/s
Tue 7 May 12:39:00 BST 2019
KB is: 136
Exiting at *** Tue 7 May 12:39:00 BST 2019
The other file, which has a name like ff.log05-07-19:12:32, looks more like this:
CPU load average is around 1 or so – much less than before. So I think my ideas are on the right track. Why send 30 frames or whatever each and every second to Youtube just to display a gray screen? The CPU has to work to do that. As long as ffmpeg + Youtube has the intelligence to paste together audio snippets 1/5th second in length five times each second the audio should be taken care of, we’re not playing with the sampling rate or anything – is how I reasoned. Key frames are some sort of overhead as well since they’re extra things ffmpeg has to periodically do. Youtube wants one at least every four seconds. We get really close to that limit by multiplying fps * 3.6 s = 5 * 3.6 = 18 for our group-of-pictures (g) parameter. Previously we were sending a key frame more frequently – every two seconds.
Unreliability
Running this command is still hit-or-miss. As often as not it hangs, and then, if it does not hang, as often as not it often outputs washboard audio. You just <Ctrl-C> to get out of it if hangs, or type “q” if it is producing washboard audio.
Note carefully the bandwidth being used, which ffmpeg reports every second. If it is < 128 kbps, you’re hosed and have washboard audio. If it’s about 135 kbps or higher, you’re good. You don’t even need to waste time fiddling with Youtube’s live_dashboard to listen to it. You get this feedback immediately from ffmpeg. And I intend to use these same observed behaviors to script around ffmpeg’s flakiness and keep restarting it automatically until it is producing a good quality audio stream!
Improved startup
This script, which I call continuousaudio.sh, has some debugging at the beginning, then loops to ensure there is always an audio stream being live-streamed as long as the Pi has power. It has been extremely reliable. I settled on this one for my own purposes.
#!/bin/sh
# drJ 5/2019
LOG="ff.log"`date +%m-%d-%y:%H:%M`
# some info for debugging problems
echo "***********"
date; ip add; ping -c2 8.8.8.8; lsusb
nohup ./ffmpegwireless6.sh > $LOG 2>&1 &
while /bin/true; do
sleep 7
# want s.th like
#Frame= 84 fps= 11 q=16.0 size= 43kB time=00:00:07.50 bitrate= 47.1kbits/s dup=0 drop=431 speed=0.991x
#Frame= 84 fps= 11 q=16.0 size= 43kB time=00:00:07.50 bitrate= 47.1kbits/s dup=0 drop=431 speed= 1x
FFOUT=`tail -1 $LOG`
# next line only for DrJ debugging - lines are long
#echo "last line is $FFOUT"
# use gawk instead of awk to parse long lines
KB=`echo $FFOUT|gawk '{print $(NF-5)" "$(NF-4)}'|sed 's/kbits.*//'|gawk '{print $NF}'`
echo "orig KB: $KB"
KB=$(echo $KB|sed s/\\..*//)
date
echo "KB is: $KB"
if [ $KB -gt 129 2>/dev/null ]; then
# stream looks good - do nothing
echo -n ""
else
# didn't work out: restart and try again
echo "*** Restarting ffmpeg at *** "`date`
pkill -9 -f 'ffmpeg '
nohup ./ffmpegwireless6.sh > $LOG 2>&1 &
fi
done
gawk
Eventually I found I needed to use gawk instead of awk in continuousaudio.sh because the number of fields exceeded the max of roughly 32700 in the line I was parsing. To install gawk:
$ sudo apt-get install gawk
Note it still calls ffmpegwireless6.sh, which I believe I have provided above.
ff.log now looks like this:
**********
Fri 31 May 01:10:59 BST 2019
1: lo: <loopback,up,lower_up> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <no-carrier,broadcast,multicast,up> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether b8:27:eb:11:fc:06 brd ff:ff:ff:ff:ff:ff
3: wlan0: <broadcast,multicast,up,lower_up> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether b8:27:eb:44:a9:53 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.170/24 brd 192.168.1.255 scope global wlan0
valid_lft forever preferred_lft forever
inet6 fe80::1119:b46a:cb69:63c9/64 scope link
valid_lft forever preferred_lft forever
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=14.6 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=17.4 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 14.671/16.065/17.460/1.400 ms
Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 005: ID 0424:7800 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
last line is frame= 19 fps=0.0 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=69 speed= 0x ^Mframe= 39 fps= 39 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=150 speed= 0x ^M
orig KB: dup=0
Fri 31 May 01:11:07 BST 2019
KB is: dup=0
*** Restarting ffmpeg at *** Fri 31 May 01:11:07 BST 2019
last line is frame= 193 fps= 35 q=8.0 size= 100kB time=00:00:27.60 bitrate= 29.6kbits/s dup=0 drop=764 speed=4.99x ^Mframe= 195 fps= 32 q=8.0 size= 108kB time=00:00:28.03 bitrate= 31.4kbits/s dup=0 drop=775 speed=4.65x ^M
orig KB: 31.4
Fri 31 May 01:11:36 BST 2019
KB is: 31
*** Restarting ffmpeg at *** Fri 31 May 01:11:36 BST 2019
...
</broadcast,multicast,up,lower_up></no-carrier,broadcast,multicast,up></loopback,up,lower_up>
**********
Fri 31 May 01:10:59 BST 2019
1: lo: <loopback,up,lower_up> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <no-carrier,broadcast,multicast,up> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether b8:27:eb:11:fc:06 brd ff:ff:ff:ff:ff:ff
3: wlan0: <broadcast,multicast,up,lower_up> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether b8:27:eb:44:a9:53 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.170/24 brd 192.168.1.255 scope global wlan0
valid_lft forever preferred_lft forever
inet6 fe80::1119:b46a:cb69:63c9/64 scope link
valid_lft forever preferred_lft forever
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=14.6 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=17.4 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 14.671/16.065/17.460/1.400 ms
Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 005: ID 0424:7800 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
last line is frame= 19 fps=0.0 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=69 speed= 0x ^Mframe= 39 fps= 39 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A dup=0 drop=150 speed= 0x ^M
orig KB: dup=0
Fri 31 May 01:11:07 BST 2019
KB is: dup=0
*** Restarting ffmpeg at *** Fri 31 May 01:11:07 BST 2019
last line is frame= 193 fps= 35 q=8.0 size= 100kB time=00:00:27.60 bitrate= 29.6kbits/s dup=0 drop=764 speed=4.99x ^Mframe= 195 fps= 32 q=8.0 size= 108kB time=00:00:28.03 bitrate= 31.4kbits/s dup=0 drop=775 speed=4.65x ^M
orig KB: 31.4
Fri 31 May 01:11:36 BST 2019
KB is: 31
*** Restarting ffmpeg at *** Fri 31 May 01:11:36 BST 2019
...
</broadcast,multicast,up,lower_up></no-carrier,broadcast,multicast,up></loopback,up,lower_up>
Portability
I wanted to record a practice session in my house where no Ethernet port is available (hence I had to get WiFi working, which I believe I have). And I wanted convenience – to not worry about being tethered to the wall by an adapter. So I decided to look for an economical power solution for Raspberry Pi. And I found the ones purpose-built are just too expensive to justify. Pijuice, I’m talking about you. So, really, I realized any old portable USB power stick would work. But I wanted something which could last hours. This Omars 10000 mAh portable USB charger seemed like it would do the trick. $16. And it did. It works great! Two hours later, the LEDs show three bars instead of four, so I think this will supply power for about 8 – 9 hours if I pushed it. And it has the form factor of a smartphone. Ideally I’d want a little on/off switch to avoid plugging/unplugging the power cable, but I didn’t find that as of yet. Maybe there’s a cheap USB cable with that…?
So now I’m not tethered by Ethernet cables nor by a power plug. See where this is progressing? If I use my smartphone’s hotspot I should be able to livestream anywhere I can get a signal, so, for instance, at band performances. I haven’t tried that yet, but I’m hopeful…
YouTube quirks
As previously mentioned (I think)( you need to be enabled for livestreaming. It takes about 24 hours for the approval. I suppose they check to make sure you aren’t a perceived threat.
Recording NPR will give you a copyright violation flag! This has happened to me more than once. I think because they play snippets of new music which are flagged.
Lag. I’ve seen lag time as short as four seconds and maybe as long as 20 seconds or so. It is never instantaneous.
My longest video was 20 hours but the processing took days. In fact I’m not sure it ever completed. So I guess the service falls apart after video lengths of I don’t know, maybe 12 hours or so. So if the desire is to have a continuous security webcam I guess you’ll have to break it into chunks. That’s what I’m thinking about next.
A livestream gets converted to a video by YouTube. That takes awhile – maybe as long as the video length itself is? It slaps a date and time onto the video which you see in your video manager. Unfortunately, using this ffmpeg streaming method it chooses the Pacific standard time timezone. I actually don’t see a simple way to change that either. It may require use of the API, which is beyond what I’m willing to tackle right now. So for me, being in the Eastern time zone all the timestamps are off by three hours, which is kind of annoying.
I wondered, does my livestream ID remain constant, or will it change from broadcast to broadcast? This is important for future use of the API. Well, it changes each time I start a new livestream, even though I use a single (my own) account. Each livestream gets a unique ID which then becomes the ID for the DVR of the video which you can view on-demand. And this ID is the part that changes in the URL of an “unpublished” Youtube video. Say your unpublished livestream is https://www.youtube.com/watch?v=r1wtZwQ-Tk8.
The part of the URL following the v=, namely, in this example, r1wtZwQ-Tk8, is the ID of that video. I would say YouTube tries to be somewhat robust and will not declare your stream has ended until maybe 30 seconds after you have stopped your program. Or maybe it’s a minute or two, I’m not really sure. But I’ve seen that if you restart the streaming quickly enough you’ll be put onto that same livestream. If on the other hand you wait long enough until you see in live_dashboard that stream ended message then It will assign yuo a new video ID if you start your stream again – and don’t forget to reload the live_dashboard page so it can pick up the new ID.
Can you pause a livestream, and later resume, keeping the same URL? In a word, No. Unfortunately. Youtube livestreaming is pretty limited in this way. And how useful would that be? I would use my smartphone to control ffmpeg on my Raspberry Pi to pause our band practice during our lengthy chat breaks, keeping the stream focussed on the music. But no… Not possible.
Logitech webcam quirks
When you pull both video and audio from your Logitech webcam the usage LED illuminates as you’d expect. However, when you’re pulling just the audio, as I show above, that LED does not illuminate, yet it is being used to record all the sounds in its vicinity. I guess I have accidentally and unintentionally stumbled upon a stealth mode, which is a little disconcerting.
Yeti USB microphone quirks
A Yeti mic is extremely sensitive and seems more suited for conversation than music recording in my opinion. Even with the gain all the way down (a must) a loud sound is often distorted. I felt the omni recording mode was the worst in this regard. Stereo recording tolerated sounds better. But, if you want to pikc up every little sound, Yeti is great. More importantly to me, it just worked with the USB settings I used for Logitech. I didn’t have to change a single thing in the way I used ffmpeg.
Testing if the livestream is still running
My idea to do this is to use the YouTube API and periodically test if the livestream is still working. I have read that it can go down for various reason, and there is no goo way from within ffmpeg itself to tell that your stream is no longer live! It will make for a good project to test the livestream using the Google Developer’s API. that will be a separate post if I ever get it working. If it’s found to be down, the Pi could restart ffmpeg, in my thinking.
To do list
I never really perfected the video. Audio I got pretty well.
I will borrow my friend’s Yeti USB mic to see how my audio stream works with a high quality microphone. DONE.
I would like to have a simple external control to turn stream off/ on, whether it is physical or virtual. DONE – see references.
Scripting to monitor stream and restart it once it fails – to have a recording 24×7 like an audio-only security camera. DONE – continuousaudio.sh as documented above.
Pause feature. PARTIALLY DONE.
Conclusion
A Raspberry Pi 3 running Raspbian Stretch Lite is used, along with a Logitech USB webcam, to livestream to YouTube. I showed how to stream video-only with a silent audio track. Then I turned it around and spent most of my time putting a virtual piece of tape over the lens and doing an audio-only livestream. This, after a crap-load of testing and tweaking, eventually began to work in a reliable fashion. Then I showed how to launch the audio-only livestream upon power-up of the Ras Pi.
Since it is a Raspberry Pi, this whole thing lends itself to portability and interesting use cases. With a $17 portable USB battery source and your own Hotspot, you can stream (audio at least) from anywhere you have 4G cell signal – good for recording a banquet, your band performance, or any other long, live event.
I spoke about some of the many quirks of YouTube which are relevant to this project.
YouTube’s links have me confused. If you’re trying to produce a Live Stream you’ll want the live dashboard page to watch it and check its quality as Youtube judges it. Here’s that link: https://www.youtube.com/live_dashboard
Intro
In my years at cybersecurity I’ve been sufficiently removed from the action that I’ve rarely been involved in an actual case. Until last night. A friend, whom I’ll call Jute, got a formal complaint about one of his hosted Windows servers.
We have detected multiple hacking attempts from your ip address 47.5.105.236 (Hilfer Online) to access our systems.
>
> Log of attempts:
> – Hack attempt failed at 2019-01-17T14:22:41.6539784Z. Attempted user name: Not specified (typical for port scanners or denial of service attacks), system accessed: RDP, ip address accessed: 158.69.241.92
> – Hack attempt failed at 2019-01-17T14:22:26.2213808Z. Attempted user name: Not specified (typical for port scanners or denial of service attacks), system accessed: RDP, ip address accessed: 158.69.241.92
> – Hack attempt failed at 2019-01-17T14:22:10.6304194Z. Attempted user name: Not specified (typical for port scanners or denial of service attacks), system accessed: RDP, ip address accessed: 158.69.241.92
>
>
> Please investigate this problem.
>
> Sent using IP Ban Pro
> http://ipban.com
Hack, cont.
I’ve changed the IPs to protect the guilty! But I’ve conveyed the specificity of the error reporting. Nice and detailed.
Jute has a Windows Server 2012 at that IP. He is not running a web server, so that conveniently and dramatically narrows the hackable footprint of his server. I ran a port scan and found ports 135, 139 and 3389 open. His provider (which is not AWS) offers a simple firewall which I suggested we use to block ports 135 and 139 which are for Microsoft stuff. He was running it as a local sever so I don’t tihnk he needed it.
Bright idea: use good ole netstat
The breakthrough came when I showed him the poor man’s packet trace:
netstat -an
from a CMD prompt. He ran that and I saw not one but two RDP connections. One we easily identified as his, but the other? It was coming form another IP belonging to the same provider! RDP is easily identified by just looking for the port 3389 connections. Clearly we had caught first-hand an unauthorized user.
I suggested a firewall rule to allow only his Verizon range to connect to server on port 3389. But, I am an enterprise guy, used to stateful firewalls. When we set it up we cut off his RDP session to his own server! Why? I quickly concluded this was amateur hour and a primitive, ip-chains-like stateless firewall. So we have to think about rules for each packet, not for each tcp connection.
Once we put in a rule to block access to ports 135 and 139, we also blocked Jute’s own RP session. So the instructions said once you use the firewall, an implicit DENY ALL is added to the bottom of the rules.
So we needed to add a rule like:
SRC: ANY DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: 3389 ACTION: allow
But his server needs to access web sites. That’s a touch difficult with a stateless firewall. You have to enter the “backwards” rule (outbound traffic is not restricted by firewall):
SRC: ANY DST: 47.5.105.236 SRC_PORT: 443 DST_PORT: ANY ACTION: allow
But he also needs to send smtp email, and look up DNS! This is getting messy, but we can do it:
SRC: ANY DST: 47.5.105.236 SRC_PORT: 25 DST_PORT: ANY ACTION: allow
SRC: ANY DST: 47.5.105.236 SRC_PORT: 53 DST_PORT: ANY ACTION: allow
We looked up the users and saw Administrator and another user Update. We did not recognize Update so he deleted it! And changed the password to Administrator.
Finally we decided we had to bump this hacker.
So we made two rules to allow him but deny the zombie computer:
SRC: 158.69.240.92 DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: 3389 ACTION: reject
SRC: ANY DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: 3389 ACTION: allow
Pyrrhic victory
Success. We bumped that user right out while permitting Jute’s access to continue. The bad news? A new interloper replaced it! 95.216.86.217.
OK. So with another rule we can bump that one too.
Yup. Another success. another interloper jumps on in its place. 124.153.74.29. So we bump that one. But I begin to suspect we are bailing the Titanic with a thimble. It’s amazing. Within seconds a blocked IP is being replaced with a new one.
We need a more sweeping restriction. So we reasoned that Jute will RP from his provider where his IP does not really change.
So we replace
SRC: ANY DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: 3389 ACTION: allow
with
SRC: 175.198.0.0/16 DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: 3389 ACTION: allow
and we also delete the specific reject rules.
But now at this point for some reason the implicit DENY ALL rule stops working. From my server I could do an nc -v 47.5.105.236 3389 and see that that port was open, though it should ont have been. So we have to add a cleanup rule at the bottom:
SRC: ANY DST: 47.5.105.236 SRC_PORT: ANY DST_PORT: ANY ACTION: reject
That did the trick. Port no longer opened.
There still appears in netstat -an listing the last interloper, but I think it just hasn’t been timed out yet. netstat -an also clearly shows (to me anyway) what they were doing: scanning large swaths of the Internet for other vulnerable servers! The tables were filled with SYN-SENT to port 3389 of consecutive IPs! Amazing.
So I think Jute’s server was turned into a zombie which was tasked with recruiting new zombies.
We had finally frozen them out.
Later that night
Late that same night he calls me in a panic. He uses a bunch of downstream servers and that wasn’t working! The downstream servers run on a range of ports 14800 – 15200.
Now bear in mind the provider only permits us 10 firewall rules, so it’s getting kind of tight. But we manage to squeeze in another rule:
SRC: ANY DST: 47.5.105.236 SRC_PORT: 14800-15200 DST_PORT: ANY ACTION: allow
He breathes a sigh of relief because this works! But I want him we are opening a slight hole now. Short term there’s nothing we can do. It’s a small exposure: 400 open ports out of 65000 possible. It should hold him for awile with any luck.
He also tried to apply all updates at my suggestion. I’m still not sure what vulnerability was (is) exploited.
Case: tentaively closed
Our first attempt to use the Windows firewall itself was not initially successful. We may return to it.
Conclusion
We catch a zombie computer totally exploiting RDP on a Windows 2012 server. We knocked it off and it was immediately repaced with another zombie doing the same thing. Their task was to find more zombies to join to the botnet. Inbound firewall rules defined on a stateless firewall were identified which stopped this exploitation while permitting desired traffic. Not so easy when you are limited to 10 firewall rules!
This is a case where IPBAN did us a favor. The system worked as it was supposed to. We got the alert, and acted on it immediately.
I’m not 100% sure which RP vulnerability was exploited. It may have been an RCE – remote code execution not even requiring a valid logon.
Intro
We had a Cisco video conference unit pick up an IP from a data vlan whereas we expected it to pick it up from a voice vlan, where we had assigned it a static IP. What happened?
The details
I have to admit I never paid attention to the switch ports in the offices. All these years and I didn’t really appreciate the fact that you can plug in either a PC or a Cisco phone to the same switch port, yet the PC “knows” to go onto a data vlan while the phone “knows” to put itself onto a voice vlan. How cuold that be?
Naively, just talking it out, I had this jumble of “facts” in my mind:
– sharing vlans on one switch port is done through vlan tagging
– the equipment plugged in must know the switch port is using vlan tagging or else disastrous results occur (see this post for some examples)
– if in addition you’re a PC using DHCP, how would you know which valn to go onto? How would you learn the connection is tagged?
– well, there can be a native vlan in addition to tagged vlans. Maybe they used that?
Fortunately I have some friends with access to the switch config. Here it is for one specific typical port:
I puzzled over that for awhile because, well, what does it mean?? In my world of servers you have two port types: access ports and truink ports. Trunk ports are the ones that have tagged vlans. Access ports provide a single unttagged vlan’s traffic to the port.
It’s pretty clearly declaring this switch port to be an access port, not a trunk port. And yet two vlans are referred to. There’s this command I’ve never seen or used before swithcport voice. How does this fit with the jumble of facts above? The jumble of facts need to be amended…
I asked another expert and he said he heard that the Cisco phones use something called LLDP – link layer discovery porotocol. From researching the predecessor protocol was CDP – Cisco Discovery protcol.
Switchport voice vlan 703 is something like introducing tagging for vlan703, if I read the Cisco documentation correctly.
The magic happens
This is often described as magic or voodoo so we will treat it like that too! A Cisco phone uses LLDP to learn from the switch that the voice vlan is 703. Then somehow it tags(?) its traffic to use only that vlan, even for its DHCP discover. A PC or any other normal host by contrast does not use LLDP and is only exposed to the data vlan 103 (the “native” vlan) so it gets an IP from doing DHCP discover on that vlan.
Do I believe my own explanation? Not really. It’s the best I got. I really should do a packet trace to confirm but who has the time?
That video conference unit? They say when they boot it a second time it jumps onto the correct vlan and picks up the desired static IP. Again, no one’s really sure why.
Conclusion
Strange DHCP behavious on the part of a Cisco video conference unit forces us to think through how data + voice on one switch port might actually be working on a typical Cisco-powered office environment. We probably – definitely – didn’t nail it, but we must be close to the essentially correct answer.
Intro I write this knowing I still don’t know anything to speak of about syslog, but, sometimes you gotta act without knowing. I needed to send syslog to somewhere in a big hurry so I figured out the absolute minimum I needed to do to get it running on one of my other systems.
The details This all started because of a deficiency in the F5 ASM. At best it’s do slow when looking through the error log. But in particular there was one error that always timed out when I tried to bring up the details, a severity 5 error, so it looked pretty important. Worse, local logging, even though it is selected, also does not work – the /var/log/asm file exists but contains basically nothing of interest. I suppose there is some super-fancy and complicated MySQL command you could run to view the logs, but that would take a long time to figure out.
So for me the simplest route was to enable remote syslog on a Linux server and send the ASM logging to it. This seems to be working, by the way.
The minimal steps Again, this was for Suse Enterprise Linux running syslog-ng.
modify /etc/sysconfig/syslog as per the next step
SYSLOGD_PARAMS=”-r”
modify /etc/syslog-ng/syslog-ng.conf as per the next step
uncomment this line: udp(ip(“0.0.0.0”) port(514));
launch yast (I use curses-based yast [no X-Windows] which is really cantankerous)
go to Security and Users -> Firewall -> Allowed services -> Internal Zone -> Advanced
add udp port 514 as additional allowed Ports in internal zone and save it
service syslog stop
service syslog start
You should start seeing entries in /var/log/localmessages as in this suitably anonymized example (I added a couple line breaks for clarity:
Observations Interestingly, there is no syslogd on this particular system, and yet the “-r” flag is designed for syslogd – it’s what turns it into a remote syslogging daemon. And yet it works.
It’s easy enough to log these messages to their own file, I just don’t know how to do it yet because I don’t need to. I learn as I need to. just as I learned enough to publish this tip.
Conclusion We have demonstrated activating the simplest possible remote syslogger on Suse Linux Enterprise Server.
Intro
I recently received revised guidelines for dmz best practices which mentioned a requirement to implement application-independent authentication using the F5 web application firewall. I had never heard of it and didn’t think it was possible without buying the very expensive APM license. They insisted it was possible and even easy to do. So I investigated and found they were right!
The details
This is a feature added around version 11.4.
On the F5, go to Local Traffic|Profiles|Authentication|Configurations and create a new configuration. Here you put in the essential LDAP information and give these settings a name such as myLDAP. I needed to set Login Attribute to cn. Then go to …Authentication|Profiles and create a new one. Set parent profile as LDAP and associate the configvuration myLDAP to it. Rule can be _sys_auth_ldap.
In the virtual server Properties tab look for the section Authentication Profiles. Pick the profile you created.
That’s it! Your virtual server now has application-independent authentication using your preferred LDAP source.
So far I only tested against an LDAP source that doesn’t require an ldap bind. But I did successfully test against an ldaps source (which runs on port 636 and encrypts the communication using SSL. I got that to work setting SSL to Enabled and essentially taking the other SSL-related default values.
Conclusion
We show how to implement application-independent authentication on an F5 BigIP which only has the local traffic manager (LTM) license. We used an LDAP directory for the authentication source. I believe a certificate mechanism would also have been possible. As it happens our LDAP source was not an Active Directory (AD) tree, but I believe it would be possible to use that as well. We also did not limit access to any specific group, but that is probably possible as well.
Intro
I was recently asked if a new certificate a web site is about to deploy would require any changes to our clients such as needing to import this certificate into their Java keystore.
The details
Well, I saved the certificate on a Linux server calling it my.crt and examined it using openssl:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
68:5f:f8:b6:5e:56:c2:1d
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2
Validity
Not Before: Apr 5 22:57:01 2018 GMT
Not After : Apr 5 22:57:01 2020 GMT
Subject: 1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=California/2.5.4.15=Private Organization/serialNumber=C2417721, C=US, ST=California, L=Carlsbad, CN=www.drj.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (4096 bit)
Modulus (4096 bit):
00:da:c7:18:a2:4d:b5:c9:95:22:b0:64:50:e7:b8:
...
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
68:5f:f8:b6:5e:56:c2:1d
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2
Validity
Not Before: Apr 5 22:57:01 2018 GMT
Not After : Apr 5 22:57:01 2020 GMT
Subject: 1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=California/2.5.4.15=Private Organization/serialNumber=C2417721, C=US, ST=California, L=Carlsbad, CN=www.drj.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (4096 bit)
Modulus (4096 bit):
00:da:c7:18:a2:4d:b5:c9:95:22:b0:64:50:e7:b8:
...
So I checked the text after the Issuer field, C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority – G2
This is the intermediate CA. And it exactly matches their current certificate we already trust. So no problem, right, we are good to go, right? Not so fast grasshopper. This certificate contains a totally new element for us. I happened to notice it has a 4096 bit key length. Never seen that before though I have heard about it.
How do we even know our old browsers and even proxy server are going to be good with that? The best way I reasoned is simply to find another site with a 4096 bit certificate. Well, it took me almost an hour before I found one, and DDG and Google searches proved fruitless. I found it by taking logical guesses, as in, surely some security-minded organization has deployed these already??
ssllabs.com. Nope. godaddy.com. Nope. www.google.com. Nope. Gnupg.org, Nah, ah. Lets Encrypt. Also a no. Then I tried nist.org and found the weirdest thing. They send several certificates, one of which is *.bluehost.com which is 4096 bits. But it makes no sense being part of the certificates on nist.org, as an ssllabs.com server eval will tell you. So then I tried www.bluehost.com. Paydirt!
$ examinecert www.bluyehost.com
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
af:a7:b9:22:4f:d5:7e:6b:78:4b:5a:23:d0:35:50:23
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server
CA
Validity
Not Before: Oct 16 00:00:00 2015 GMT
Not After : Oct 17 23:59:59 2018 GMT
Subject: OU=Domain Control Validated, OU=Hosted by BlueHost.Com, INC, OU=PositiveSSL Wildcard, CN=*.unifiedlayer.co
m
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:c5:2b:10:d2:20:bb:d9:1b:e1:d3:b2:d1:9b:6f:
...
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
af:a7:b9:22:4f:d5:7e:6b:78:4b:5a:23:d0:35:50:23
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server
CA
Validity
Not Before: Oct 16 00:00:00 2015 GMT
Not After : Oct 17 23:59:59 2018 GMT
Subject: OU=Domain Control Validated, OU=Hosted by BlueHost.Com, INC, OU=PositiveSSL Wildcard, CN=*.unifiedlayer.co
m
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:c5:2b:10:d2:20:bb:d9:1b:e1:d3:b2:d1:9b:6f:
...
examinecert is a bash function I created defined as:
And for this company that brings up a host of questions. if their again IE 11 has never encountered a web site with this long of a key length, how will we know what will happen the first time?
Also, some sites get SSL intercepted by Bluecoat proxy. How will that infrastructure handle it? Will it handle it?
That;s why it was so important to find a real-world example, as painful as that exercise proved to be.
The answers are somewhat surprising.
Yes, ancient Internet Explorer probably handles 4096 bit key lengths just fine. I actually haven’t fully tested that one yet.
But it doesn’t matter for this company. Their Bluecoat proxy intercepts the SSL. So, yes, that part works, and re-creates its own certificate, but issued as a standard 2048-bit key length! So that is what IE sees so I know there will be no issue there. I say surprising because usually the generated certificates so carefully preserve all aspects of a certificate: same expiration date, same common name, etc. Whether or not this key length reduction is configurable or not I have yet to find out.
Follow up
As a result of my prodding, badssl.com will include a 4096-bit certificate with which to test things out.
Conclusion
After an arduous search (I’m sure next year this time this will become much easier) we found a public site which can be used to test 4096 bit key lengths: www.bluehost.com. Obviously GoDaddy also issues 4096-bit certificates since that is what this particular web site uses as their issuer, but I have yet to find an actual live example of one.
Bluecoat SSL interception by default does handle this long key length, but generates its private version of it with only a 2048 key length, to our surprise.
Just remember, if you have a Raspberry Pi you can run all these commands that I’ve shown because you have a bone fide Linux system.
Intro
Did you ever want to learn about a domain registration but were put off by the hard sell tactics that basically all web-based whois searches subject you to? Me, too. Here’s what you can do.
The details
Linux – so that includes you, Raspberry Pi owners – has a little utility called whois which you can use to get the registrant information of a domain, e.g.,
Domain Name: JOHNSTECHTALK.COM
Registry Domain ID: 1795918838_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.godaddy.com
Registrar URL: http://www.godaddy.com
Updated Date: 2017-03-27T00:52:50Z
Creation Date: 2013-04-23T00:54:17Z
Registrar Registration Expiration Date: 2019-04-23T00:54:17Z
Registrar: GoDaddy.com, LLC
Registrar IANA ID: 146
Registrar Abuse Contact Email: [email protected]
Registrar Abuse Contact Phone: +1.4806242505
Domain Status: clientTransferProhibited http://www.icann.org/epp#clientTransferProhibited
Domain Status: clientUpdateProhibited http://www.icann.org/epp#clientUpdateProhibited
Domain Status: clientRenewProhibited http://www.icann.org/epp#clientRenewProhibited
Domain Status: clientDeleteProhibited http://www.icann.org/epp#clientDeleteProhibited
Registry Registrant ID: Not Available From Registry
Registrant Name: ******** ******** (see Notes section below on how to view unmasked data)
Registrant Organization:
Registrant Street: ***** ****
Registrant City: Newton
Registrant State/Province: New Jersey
Registrant Postal Code: 078**
Registrant Country: US
Registrant Phone: +*.**********
Registrant Phone Ext:
Registrant Fax:
Registrant Fax Ext:
Registrant Email: ********@*****.***
Registry Admin ID: Not Available From Registry
Admin Name: ******** ******** (see Notes section below on how to view unmasked data)
...
Domain Name: JOHNSTECHTALK.COM
Registry Domain ID: 1795918838_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.godaddy.com
Registrar URL: http://www.godaddy.com
Updated Date: 2017-03-27T00:52:50Z
Creation Date: 2013-04-23T00:54:17Z
Registrar Registration Expiration Date: 2019-04-23T00:54:17Z
Registrar: GoDaddy.com, LLC
Registrar IANA ID: 146
Registrar Abuse Contact Email: [email protected]
Registrar Abuse Contact Phone: +1.4806242505
Domain Status: clientTransferProhibited http://www.icann.org/epp#clientTransferProhibited
Domain Status: clientUpdateProhibited http://www.icann.org/epp#clientUpdateProhibited
Domain Status: clientRenewProhibited http://www.icann.org/epp#clientRenewProhibited
Domain Status: clientDeleteProhibited http://www.icann.org/epp#clientDeleteProhibited
Registry Registrant ID: Not Available From Registry
Registrant Name: ******** ******** (see Notes section below on how to view unmasked data)
Registrant Organization:
Registrant Street: ***** ****
Registrant City: Newton
Registrant State/Province: New Jersey
Registrant Postal Code: 078**
Registrant Country: US
Registrant Phone: +*.**********
Registrant Phone Ext:
Registrant Fax:
Registrant Fax Ext:
Registrant Email: ********@*****.***
Registry Admin ID: Not Available From Registry
Admin Name: ******** ******** (see Notes section below on how to view unmasked data)
...
So now we’re getting somewhere. So GoDaddy tries to force you to their web page an sell you stuff in any case. Not at all surprising for anyone who’s ever been a GoDaddy customer (includes yours truly). Because that’s what they do. But not all registrars do that.
Here’s a real-life example which made me decide this technique should be more broadly disseminated. I searched for information on a domain in Argentina:
$ whois buenosaires.com.ar
This TLD has no whois server, but you can access the whois database at
http://www.nic.ar/
This TLD has no whois server, but you can access the whois database at
http://www.nic.ar/
Now if you actually try their suggested whois server, it doesn’t even work:
$ whois ‐h www.nic.ar buenosaires.com.ar
Timeout.
Timeout.
What you can do to find the correct whois server is use iana – Internet Assigned Numbers Authority – namely, this page:
So for Argentina I clicked on .ar (I expected to find a separate listing for .com.ar but that was not the case), leading to the page:
See it? At the bottom it shows Whois server: whois.nic.ar. So I try that and voila, meaningful information is returned, no ads accompanying:
$ whois ‐h whois.nic.ar buenosaires.com.ar
% La información a la que estás accediendo se provee exclusivamente para
% fines relacionados con operaciones sobre nombres de dominios y DNS,
% quedando absolutamente prohibido su uso para otros fines.
%
% La DIRECCIÓN NACIONAL DEL REGISTRO DE DOMINIOS DE INTERNET es depositaria
% de la información que los usuarios declaran con la sola finalidad de
% registrar nombres de dominio en ‘.ar’, para ser publicada en el sitio web
% de NIC Argentina.
%
% La información personal que consta en la base de datos generada a partir
% del sistema de registro de nombres de dominios se encuentra amparada por
% la Ley N° 25326 “Protección de Datos Personales” y el Decreto
% Reglamentario 1558/01.
domain: buenosaires.com.ar
registrant: 50030338720
registrar: nicar
registered: 2012-07-05 00:00:00
changed: 2017-06-27 17:42:45.944889
expire: 2018-07-05 00:00:00
contact: 50030338720
name: TRAVEL RESERVATIONS SRL
registrar: nicar
created: 2013-09-05 00:00:00
changed: 2018-04-17 13:14:55.331068
nserver: ns-1588.awsdns-06.co.uk ()
nserver: ns-925.awsdns-51.net ()
nserver: ns-1385.awsdns-45.org ()
nserver: ns-239.awsdns-29.com ()
registrar: nicar
created: 2016-07-01 00:02:28.608837
% La información a la que estás accediendo se provee exclusivamente para
% fines relacionados con operaciones sobre nombres de dominios y DNS,
% quedando absolutamente prohibido su uso para otros fines.
%
% La DIRECCIÓN NACIONAL DEL REGISTRO DE DOMINIOS DE INTERNET es depositaria
% de la información que los usuarios declaran con la sola finalidad de
% registrar nombres de dominio en ‘.ar’, para ser publicada en el sitio web
% de NIC Argentina.
%
% La información personal que consta en la base de datos generada a partir
% del sistema de registro de nombres de dominios se encuentra amparada por
% la Ley N° 25326 “Protección de Datos Personales” y el Decreto
% Reglamentario 1558/01.
domain: buenosaires.com.ar
registrant: 50030338720
registrar: nicar
registered: 2012-07-05 00:00:00
changed: 2017-06-27 17:42:45.944889
expire: 2018-07-05 00:00:00
contact: 50030338720
name: TRAVEL RESERVATIONS SRL
registrar: nicar
created: 2013-09-05 00:00:00
changed: 2018-04-17 13:14:55.331068
nserver: ns-1588.awsdns-06.co.uk ()
nserver: ns-925.awsdns-51.net ()
nserver: ns-1385.awsdns-45.org ()
nserver: ns-239.awsdns-29.com ()
registrar: nicar
created: 2016-07-01 00:02:28.608837
2nd example: goto.jobs
I actually needed this one! So I learned of a domain goto.jobs and I wanted to get some background. So here goes…
$ whois goto.jobs
getaddrinfo(jobswhois.verisign-grs.com): Name or service not known
getaddrinfo(jobswhois.verisign-grs.com): Name or service not known
So off to a bad start, right? So we hit up the .jobs link on iana, https://www.iana.org/domains/root/db/jobs.html, and we spy a reference to their whois server:
Registry Information
This domain is managed under ICANN's registrar system. You may register domains in .JOBS through an ICANN accredited registrar. The official list of ICANN accredited registrars is available on ICANN's website.
URL for registration services: http://www.goto.jobs
WHOIS Server: whois.nic.jobs
Registry Information
This domain is managed under ICANN's registrar system. You may register domains in .JOBS through an ICANN accredited registrar. The official list of ICANN accredited registrars is available on ICANN's website.
URL for registration services: http://www.goto.jobs
WHOIS Server: whois.nic.jobs
So we try that:
$ whois ‐h whois.nic.jobs goto.jobs
Domain Name: GOTO.JOBS
Registry Domain ID: 91478530_DOMAIN_JOBS-VRSN
Registrar WHOIS Server: whois-all.nameshare.com
Registrar URL: http://www.nameshare.com
Updated Date: 2018-03-29T20:08:46Z
Creation Date: 2010-02-04T23:54:33Z
Registry Expiry Date: 2019-02-04T23:54:33Z
Registrar: Name Share, Inc
Registrar IANA ID: 667
Registrar Abuse Contact Email:
Registrar Abuse Contact Phone:
Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
Name Server: KATE.NS.CLOUDFLARE.COM
Name Server: MARK.NS.CLOUDFLARE.COM
Name Server: NS1.REGISTRY.JOBS
Name Server: NS2.REGISTRY.JOBS
DNSSEC: unsigned
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2018-04-23T18:54:31Z <<<
Domain Name: GOTO.JOBS
Registry Domain ID: 91478530_DOMAIN_JOBS-VRSN
Registrar WHOIS Server: whois-all.nameshare.com
Registrar URL: http://www.nameshare.com
Updated Date: 2018-03-29T20:08:46Z
Creation Date: 2010-02-04T23:54:33Z
Registry Expiry Date: 2019-02-04T23:54:33Z
Registrar: Name Share, Inc
Registrar IANA ID: 667
Registrar Abuse Contact Email:
Registrar Abuse Contact Phone:
Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
Name Server: KATE.NS.CLOUDFLARE.COM
Name Server: MARK.NS.CLOUDFLARE.COM
Name Server: NS1.REGISTRY.JOBS
Name Server: NS2.REGISTRY.JOBS
DNSSEC: unsigned
URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
>>> Last update of WHOIS database: 2018-04-23T18:54:31Z <<<
Better, but it seems to merely point to a registrar and its whois server:
Bingo! We have hit pay dirt. We have meaningful information about the registrant – an address, phone number and email address – and received no obnoxious ads in return. For me it’s worth the extra steps.
ICANN: another alternative
Most registrar’s whois sites are rate-limited. ICANN’s is not. And they also do not sic ads on you. It is
https://whois.icann.org/en/lookup?name=
ICANN, for the record, it the body that decides what goes on in DNS namespace, for instance, what new gTLDS should be added. You can use its whois tool for all gTLDs, but not in general for ccTLDs.
whois is undergoing changes due to GDPR. Especially the “social” information of the contacts: registrant, admin and technical contacts will be masked, except for perhaps state and country, in the future. But whois is slowly dying and a new standard called RDAP will take its place.