Tuesday, July 27, 2021

IP lookup in CIDR blocks

(image taken from the cidranger site)

 

Lately we've had a new requirement in our system: whitelist IPs.

This means that whenever a new client request arrives to our service, our system should first look fo the client IP in a predefined list of IPs, and in case the IP exists, the system should allow it to pass without any validations.

This sounded quite simple, until I've realized that the whitelist IPs is not a list of IPs, but a list of CIDRs, for example: 

1.2.3.0/24

While I could create a new code to scan the whitelist, and check inclusion within any subnet, it would had been very inefficient, especially considering the whitelist is ~1K long.

The solution for this is to represent the entire whitelist as a Trie, and then simply look for the IP in the trie.

Building the Trie is O(N) where N is the length of the whitelist, while searching the IP in the entire whitelist Trie, is O(number of bits in a IP) ~= O(1).

Luckily, I am not the first one who needed this, and I've found the cidranger GO library.


The following is an example of building the Trie:



cidrs := []string{"1.2.3.0/24", "1.1.1.1", "1.1.1.2/32"}

ranger := cidranger.NewPCTrieRanger()
for _, cidr := range cidrs {
if !strings.Contains(cidr, "/") {
if strings.Contains(cidr, ":") {
cidr += "/128"
} else {
cidr += "/32"
}
}

_, parsedCidr, err := net.ParseCIDR(cidr)
if err != nil {
panic(err)
}

err = ranger.Insert(cidranger.NewBasicRangerEntry(*parsedCidr))
if err != nil {
panic(err)
}
}



To lookup in IP, use the following code:



parsedIp := net.ParseIP("1.2.3.7")
included, err := ranger.Contains(parsedIp)
if err != nil {
panic(err)
}

fmt.Printf("IP included: %v",included)



It worth mentioning the library supports both IPv4 and IPv6.




Wednesday, July 21, 2021

Disk Space issues in Ubuntu VM

 


In this post we will review how to overcome disk space issues in an Ubuntu VM.

This week, we've had our build machine out of disk space due to docker images disk requirements. This occurred since we keep the latest version per each git branch. Even after cleanup of some old images, we realized that we should have more disk space available on the build machine.

The steps to add disk space are listed below.


Add New Disk to the VM

Use the VM management tools to add new disk to the VM.
Notice: reboot the machine after this, to make the OS identify the new added disk.

Create a Partition and a FileSystem

Identify the new added disk using the command: sudo lshw -C disk

An example of output is:



In this case the new disk device is /dev/sdb, which is a shorthand for Scsi Disk B.

To create a partition, run sudo cgdisk /dev/sdb, where the argument is the new disk device. 

  • In the cgdisk utility, create a new partition. 
  • Use the defaults values for the partition creation.
  • Make sure to select "Write" option after the partition creation.

Next we create a filesystem using the command: sudo mkfs -t ext4 /dev/sdb1
Find the UUID of the new filesystem using: sudo blkid | grep /dev/sdb1.
For example:



Copy the UUID, and edit the fstab: sudo vi /etc/fstab.

Duplicate one of the UUID line, and replace the UUID with the one created in the previous step. Also select an existing folder to mount the disk on. In our case we use a new folder for the docker images, hence we use the folder /var/lib/docker/overlay2.




To check that this is working, use the command: sudo mount -av.

Finally reboot the machine to verify that everything works.






Open the Default Mail Client from JavaScript


 


In this post we will review how to open the default mail client on an end user machine using javascript from a site. We want the email to be created in a new window, so the current site does not disappear after sending the email. This is just a small effort, but so unclear, that it worth mentioning.



const encodedSubject = encodeURIComponent('My Subject')

const encodedBody = encodeURIComponent(`The email body.
New
lines
can
be
included
here
`)

const link = `mailto:you@company.com?subject=${encodedSubject}&body=${encodedBody}`
window.open(text, '_blank')



Wednesday, July 7, 2021

Break the Glass




 

This post is another small change I've made as part of lesson learnt from the Google SRE book.

See this post for more details.


Some of our produce management functions are dangerous for the production environment. For example, we have several buttons to reset the system state in case of a non-recoverable problem. For example, one of these buttons will reset the production redis cluster.

These buttons a crucial in case of an emergency situation, but in case of a normal system operation might cause unnecessary damage. I've decided to use the SRE's "Break the glass" method for these buttons. By using it, i mean literally...


So I've created a small react component to protect the emergency buttons. This component can wrap any set of react children. It protects the components by hiding them behind a glass, which is broken only when the user clicks multiple times on the items.


glass.js

import React, {useState} from 'react'
import {Behind, GlassCover, Root} from './style'

function Glass(props) {
const {children} = props
const [count, setCount] = useState(0)
const max = 4

function clickHandler() {
if (count === max) {
alert('The Glass is Broken')
}

setCount(count + 1)
}


let zIndex = 10
if (count > max) {
zIndex = -1
}

return (
<Root>
<GlassCover
opacity={count / max}
zIndex={zIndex}
src={process.env.PUBLIC_URL + '/glass.png'}
onClick={clickHandler}
>

</GlassCover>
<Behind>
{children}
</Behind>
</Root>
)
}

export default Glass


We have the styled components CSS as well:


style.js

import styled from 'styled-components'

export const Root = styled.div`
position: relative;
`


export const GlassCover = styled.img`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
${({zIndex}) => `
z-index: ${zIndex};
`}
${({opacity}) => `
opacity: ${opacity};
`}
`

export const Behind = styled.div`
`


And the image, is the same image which appears in the post header.

Feel free to use...