Whiteboarding From Home difficult?

Whiteboarding From Home difficult?

So many of us are working from home now; COVID19 has changed the way we work in a very rapid way and Work From Home has become a common fact for many of us. Personally I have been working from home almost since the start of my career , way back. Reason was simple, we had a home office and were a family business. One thing that has always made me want to go to a customer or talk with a team is to have the ability to whiteboard a design or solution to a problem.

And that is something which is in my opinion very difficult with Webex and Zoom. Sure, there are corporate solutions around, like Desk pro, Webex Board, etc. And I will be honest, they look great. But they just don’t work in a smaller work from home environment/situation.

 

And until recently I just accepted the fact that Whiteboarding from Home as a feature wasn’t going to happen soon, and just had to accept it. Well, until I asked around and my fellow Cisco Champion Matt Ouellette shared his solution with me. The solution is based on the Apple ecosystem and what you need are:

 

  • MacBook Pro with latest MacOS
  • iPad that supports an Apple Pencil
  • Apple Pencil
  • Your favorite drawing app on you iPad (I am using Paper, but you could use any tool, like MS OneNote)

And here’s how to do it:

  1. First connect (physically) your iPad to your Mac and trust the computer
  2. Now that the Mac is trusted, your iPad screen has become a media source within Quicktime, so launch Quicktime Player.
  3. Click File -> New Movie Recording and click on the small triangle just right next to the record button
  4. Select your iPad as source
  5. Now go to your favorite video conferincing tool and share your desktop or juist quicktime player
  6. Go back to the iPad, start your favorite drawing App and start drawing

Agreed, it is not a collaborative way of Whiteboarding, that someone in the meeting can co-whiteboard with me, but it allows me to draw designs and solutions based on what we are talking about like I am standing in front a virtual whiteboard . What I like is that you don’t even need to record it, you can just show it. Save the diagrams for after the meeting and you have great sketches to start writing documentation with.

I am really happy with this, because it allows me to create videos and explain while drawing in the courses that I am preparing too, so thanks Matt for the tip. I have been using this a few times already over the past days!

Tampering Visibility by Tempered Networks Airwall Solution

Tampering Visibility by Tempered Networks Airwall Solution

“Personal Note: Ok, this post has been lying around in my draft for quite some time. Sorry for that Tom, Ben, and Tempered. Too many reasons but one of them is also that the folks at Tempered were so kind to allow me a trial for a few months. I will share my experiences in a few posts to come. “

I don’t know if the organizers of Security Field Day 3 did this on purpose, but it looks like they kept a very innovative solution as encore with Tempered Networks. Their presentation was the last one in the line-up and presentations. And since I hadn’t heard about their company name, I looked them up in advance and was intrigued in how they could twist the tale on security without visibility. Todays common sensus in security is that you need to see and know what is happening on your network; Tempered says: what you cannot see, you cannot hack.

Personally I think their solution originated from the IoT/OT network environment where applying security to IoT devices is well, near impossible. The S of security is lacking in IoT for a reason. I can assure you, also from my own environment, that many IoT/OT devices do not follow RFC’s completely, let alone implement IEEE standards like Port-Based Network Access Control (IEEE 802.1X). Their paradigm is that if you place one or more sensors of such an OT network behind a device that basically hides / blinds them from the rest of the IT network, and create an overlay to wherever you have servers they need to connect to, again protected by either a hardware device or software, the communication between the two endpoints is both secure and hidden. Those ports, with often unencrypted traffic, are just not available to the generic IT network and thus less prone to intrusion events.

Their solution consists of Airwall agents that run on almost any client OS (ok, ChromeOS is a different story for any client) , hardware solutions (called gateways with also added functionality), Airwall Server agents that you can run on server OS like Linux, and a conductor from which you manage the clients and settings. Secure tunnels are created between two airwalls if traffic is allowed and defined in the conductor. That is quite similar to SD-WAN solutions or VPN solutions, isn’t it?

 

However, there is a big but in here too. Airwall gateways can also act / be configured as relay client. In other words, if two airwall clients (for example an agent and server) cannot contact each other directly (NAT, twice-NAT or port-blocking), and both airwall clients can connect to a third client, that third client will act as a relay point for the traffic between the two clients, it is like a smart SD-WAN Hub/Spoke and Mesh network combined! And I can share something with you, it really works.

The screenshot below shows a group I created to allow access to a virtual server with a relay VM that allows traffic between my mobile clients and that server.

In summary, I think that Airwall is one of the first true SASE clients out there, enabling end user devices (close to anyone) connectivity to any cloud, virtual server, or datacenter with some clicks inside the Conductor. I will be honest, the folks at Tempered have shared an evaluation license so that I can test out their software and solution for a few months. I have been testing it out over the past months and will share some use cases and setup experiences in a few upcoming posts.

Swift, JSON Encoding/Decoding and subclasses

Swift, JSON Encoding/Decoding and subclasses

Over the past weeks I have been preparing for two CiscoLive Barcelona breakout sessions. In one of them I will give a brief demo and the other session where I will be covering parts of the Cisco Press book that I wrote. The preparation itself is not only about the slides, but also developing code that is to be used in the demo’s. These demo’s are built on iOS devices and run on some containers, so I have been writing that software in Swift, which is a beautiful and powerful programming language. One of my previous posts covers some principles of Swift. One really powerful feature is the easy capability to encode or decode data to the JSON format.  

If you want to have a class to be able to convert to and from a JSON format, just use the Codable protocol and you’re ready, see the code example below:

/*
 * Enumeration of supported message types. Extend this for new messages
 */
enum MessageType : Int, Codable {
    case unknown = 0            // default, unknown
    case acknowledgement = 255  // acknowledgement to message, if required
    case hello = 1              // hello, for keep alive, always followed by ack
    case sendMessage = 2        // send a unicast message to another client
    case broadcast = 3          // send a message to all connected clients
}

/*
 * Generic parent class
 * Every message has the following attributes
 * Version: To define which version we are talking about
 * Command of the message
 * client-id that sends the message
 */ unique request id, used for acknowledging, etc..
class Message : Codable, prettyPrint  {
    var version : String = "1.0"
    var msgType : MessageType = .unknown
    var clientId: String = "" // client host, generated by the server to guarantee
    var requestId: String = UUID.init().uuidString  // unique request id for this message, used in the ack
    
    // Default constructor
    // Not used cause calling super.init can override msgType value
    init() {
        // empty on purpose
    }
}
This code example defines a class message with variables for messageType (of type MessageType), requestId, which is a unique UUID string value, and a data variable which can contain any String. So let’s say I create a new message , called hello with the data “Hello there!” with the following code sample:
let msg = Message()
msg.msgType = .hello
msg.data = "Hello There!"

To convert this to JSON, this would only require a few lines of code:

let encoder = JSONEncoder()
let jsonData = try encoder.encode(msg)

The variable jsonData (of type Data) now contains a JSON-version of the earlier created message. Just to check the output, I can use the following commands to convert that data to String and output it in XCode’s Playground. 

let jsonDataAsString = String(data: jsonData, encoding: .utf8)

Suppose you would like to extend our message class with a special broadcast message, where the message can be sent to a all endpoints.. You could add an optional broadcastContent variable to the message class and create a state machine to determine when to use that value. Another alternative is to leverage the power of object-oriented programming and create a new subtype, like the following code example:

/*
 * BroadcastMessage is used to broadcast a message to all connected clients
 */
class BroadcastMessage : Message {
    // response message
    var msgContent : String = ""   // Message to broadcast   
}

So when you’d create a multicast message, like below, you’d expect that it would contain all attributes in the json file, right? Let’s check it out in Playground:

As you can see, the output does not contain all attributes of the broadcast message! It only contains the base message type class values. The msgContent variable is not included. It took me some time debugging and researching to figure out what happens. Swift bug SR-5431 and SR-4722  provide more details. Without going into those bugs, it comes down to the fact that as soon as you subclass a class that conforms to Codable, you need to override the default encode/decode methods and write your own. After some fiddling around, I have used the following code pattern to achieve that result.

/* Generic parent class
 * Every message has the following attributes
 * Version: To define which version we are talking about
 * Command of the message
 * client-id that sends the message
 * unique request id, used for acknowledging, etc..
 */
class Message : Codable, prettyPrint  {
    var version : String = "1.0"
    var msgType : MessageType = .unknown
    var data: String = "" // client host, generated by the server to guarantee
    var requestId: String = UUID.init().uuidString  // unique request id for this message, used in the ack
    
    private enum CodingKeys: CodingKey {
        case version, msgType, data, requestId
    }
    
    
    // Default constructor
    // Not used cause calling super.init can override msgType value
    init() {
        // empty on purpose
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        version = try container.decode(String.self, forKey: .version)
        msgType = try container.decode(MessageType.self, forKey: .msgType)
        data = try container.decode(String.self, forKey: .data)
        requestId = try container.decode(String.self, forKey: .requestId)
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(version, forKey: .version)
        try container.encode(msgType, forKey: .msgType)
        try container.encode(data, forKey: .data)
        try container.encode(requestId, forKey: .requestId)
    }
}

/*
 * BroadcastMessage is used to broadcast a message to all connected clients
 */
class BroadcastMessage : Message {
    // response message
    var msgContent : String = ""   // Message to broadcast
    
    // coding keys enumeration used for JSON encoding/decoding
    private  enum CodingKeys: CodingKey {
        case msgContent
    }
    
    // set class variables
    private func initClassVars() {
        self.msgType = .broadcast
        msgContent = ""
    }
    
    // default constructor. Call the parent and set variables
    override init() {
        super.init()
        initClassVars()
    }
    
    // Constructor used to instantiate a class from JSON Data
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        msgContent = try container.decode(String.self, forKey: .msgContent)
        try super.init(from: decoder)
    }
    
    // Method used to encode class to JSON
    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(msgContent, forKey: .msgContent)
        try super.encode(to: encoder)
    }
}

As you can see, when BroadcastMessage is converted to JSON, it is now correctly encoded.

I am now using the coding pattern below to achieve this functionality:

  • Create a private enum called CodingKeys that follows CodingKey. ]
  • Enter all class variables as part of the enumeration
  • Create custom encoders and decoders for the base class
  • In the subclass, define a new private enum called CodingKeys . I have marked both private so the compiler knows which variable to know in which function
  • Create the custom encoders
  • Encode the variables of the child class and then
  • Call the encoder / decoder of the parent class