Tutorial

New updates and improvements to Roundfleet.

Important notice

The code examples and scripts provided in these tutorials are for educational purposes only. Roundfleet is not responsible for any issues, damages, or security vulnerabilities that may arise from the use, modification, or implementation of these examples. Always review and test code in a secure environment before using it in production systems.

Device Location Tracking on macOS

Track and monitor the geographical location of your Roundfleet devices using IP address geolocation services. This tutorial covers location discovery, security monitoring, geofencing policies, and compliance reporting for enterprise device management.

Understanding IP-Based Location Tracking

IP geolocation provides valuable information about device location and network environment, essential for enterprise security and compliance. This method tracks devices based on their internet connection rather than GPS, making it suitable for fleet management and security monitoring.

Key Information Retrieved

  • IP Address - Public IP address of the device
  • Geographic Location - City, region, and country
  • Coordinates - Latitude and longitude for mapping
  • Network Provider - ISP or organization details
  • Timezone - Local timezone information
  • Security Context - Network environment assessment

Basic Location Discovery

Simple IP Geolocation

#!/bin/bash

# Basic location lookup using IP address
curl -s https://ipinfo.io

echo "Location information retrieved successfully"

Enhanced Location Query

#!/bin/bash

# Enhanced location discovery with formatted output
get_device_location() {
    echo "πŸ“ Retrieving device location information..."
    
    # Query location data
    local location_data
    location_data=$(curl -s https://ipinfo.io)
    
    if [[ $? -eq 0 && -n "$location_data" ]]; then
        echo "βœ… Location data retrieved successfully:"
        echo "$location_data" | jq '.' 2>/dev/null || echo "$location_data"
    else
        echo "❌ Failed to retrieve location information"
        return 1
    fi
}

# Execute location discovery
get_device_location

Structured Location Information

#!/bin/bash

# Parse and display structured location information
parse_location_data() {
    echo "🌍 Device Location Analysis"
    echo "=========================="
    
    # Get location data
    local location_json
    location_json=$(curl -s https://ipinfo.io)
    
    if [[ $? -ne 0 ]]; then
        echo "❌ Failed to retrieve location data"
        return 1
    fi
    
    # Parse individual fields
    local ip city region country loc org timezone
    ip=$(echo "$location_json" | jq -r '.ip // "Unknown"')
    city=$(echo "$location_json" | jq -r '.city // "Unknown"')
    region=$(echo "$location_json" | jq -r '.region // "Unknown"')
    country=$(echo "$location_json" | jq -r '.country // "Unknown"')
    loc=$(echo "$location_json" | jq -r '.loc // "Unknown"')
    org=$(echo "$location_json" | jq -r '.org // "Unknown"')
    timezone=$(echo "$location_json" | jq -r '.timezone // "Unknown"')
    
    # Display formatted information
    echo "πŸ”— IP Address: $ip"
    echo "πŸ™οΈ  City: $city"
    echo "πŸ—ΊοΈ  Region: $region"
    echo "🌎 Country: $country"
    echo "πŸ“ Coordinates: $loc"
    echo "🏒 Organization: $org"
    echo "πŸ• Timezone: $timezone"
    
    # Additional security information
    echo ""
    echo "πŸ”’ Security Assessment:"
    if [[ "$org" == *"VPN"* ]] || [[ "$org" == *"Proxy"* ]]; then
        echo "  ⚠️  Potential VPN/Proxy detected"
    else
        echo "  βœ… Direct internet connection"
    fi
}

# Execute location parsing
parse_location_data

Advanced Location Tracking

Multi-Source Location Verification

#!/bin/bash

# Verify location using multiple geolocation services
verify_location_multi_source() {
    echo "πŸ” Multi-source location verification..."
    
    # Service 1: ipinfo.io
    echo "Checking ipinfo.io..."
    local ipinfo_data
    ipinfo_data=$(curl -s https://ipinfo.io)
    
    # Service 2: ipapi.co (alternative)
    echo "Checking ipapi.co..."
    local ipapi_data
    ipapi_data=$(curl -s https://ipapi.co/json/)
    
    # Service 3: ip-api.com (backup)
    echo "Checking ip-api.com..."
    local ipapi_alt_data
    ipapi_alt_data=$(curl -s http://ip-api.com/json/)
    
    # Compare results
    echo ""
    echo "πŸ“Š Location Verification Results:"
    echo "================================="
    
    if [[ -n "$ipinfo_data" ]]; then
        echo "ipinfo.io Results:"
        echo "$ipinfo_data" | jq '.city, .region, .country' 2>/dev/null || echo "$ipinfo_data"
        echo ""
    fi
    
    if [[ -n "$ipapi_data" ]]; then
        echo "ipapi.co Results:"
        echo "$ipapi_data" | jq '.city, .region, .country_name' 2>/dev/null || echo "$ipapi_data"
        echo ""
    fi
    
    if [[ -n "$ipapi_alt_data" ]]; then
        echo "ip-api.com Results:"
        echo "$ipapi_alt_data" | jq '.city, .regionName, .country' 2>/dev/null || echo "$ipapi_alt_data"
    fi
}

# Execute multi-source verification
verify_location_multi_source

Location Change Detection

#!/bin/bash

# Monitor and detect location changes
monitor_location_changes() {
    local previous_location_file="/tmp/last_known_location.json"
    local current_location
    
    echo "πŸ“± Monitoring device location changes..."
    
    # Get current location
    current_location=$(curl -s https://ipinfo.io)
    
    if [[ $? -ne 0 ]]; then
        echo "❌ Failed to retrieve current location"
        return 1
    fi
    
    # Check if previous location exists
    if [[ -f "$previous_location_file" ]]; then
        local previous_location
        previous_location=$(cat "$previous_location_file")
        
        # Compare locations
        local current_city previous_city
        current_city=$(echo "$current_location" | jq -r '.city // "Unknown"')
        previous_city=$(echo "$previous_location" | jq -r '.city // "Unknown"')
        
        if [[ "$current_city" != "$previous_city" ]]; then
            echo "🚨 Location change detected!"
            echo "Previous: $previous_city"
            echo "Current: $current_city"
            
            # Log the change
            echo "$(date): Location changed from $previous_city to $current_city" >> /var/log/location_changes.log
        else
            echo "βœ… No location change detected"
        fi
    else
        echo "πŸ“ First time location check - saving baseline"
    fi
    
    # Save current location as previous
    echo "$current_location" > "$previous_location_file"
}

# Execute location monitoring
monitor_location_changes

Enterprise Location Management Script

#!/bin/bash

# Roundfleet Device Location Management System
# Comprehensive location tracking and security monitoring for enterprise devices

# Configuration
LOG_FILE="/var/log/roundfleet_location.log"
CONFIG_FILE="/etc/roundfleet/location_policy.conf"
LOCATION_DB="/var/lib/roundfleet/location_history.db"
ALERT_THRESHOLD_MILES=100

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories and files
setup_environment() {
    sudo mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
    sudo mkdir -p "$(dirname "$CONFIG_FILE")" 2>/dev/null
    sudo mkdir -p "$(dirname "$LOCATION_DB")" 2>/dev/null
    
    # Create location database if it doesn't exist
    if [[ ! -f "$LOCATION_DB" ]]; then
        echo "timestamp,ip,city,region,country,lat,lon,org,timezone" > "$LOCATION_DB"
    fi
}

# Load configuration
load_config() {
    if [[ -f "$CONFIG_FILE" ]]; then
        source "$CONFIG_FILE"
        log_action "Configuration loaded from $CONFIG_FILE"
    else
        # Default configuration
        LOCATION_TRACKING_ENABLED=true
        GEOFENCE_ENABLED=false
        ALLOWED_COUNTRIES=("US" "CA" "GB")
        BLOCKED_NETWORKS=("VPN" "TOR" "PROXY")
        MONITORING_INTERVAL=3600  # 1 hour
        REPORT_EMAIL="[email protected]"
        
        log_action "Using default location configuration"
    fi
}

# Get comprehensive location information
get_location_info() {
    local provider="${1:-ipinfo.io}"
    
    case "$provider" in
        "ipinfo.io")
            curl -s https://ipinfo.io
            ;;
        "ipapi.co")
            curl -s https://ipapi.co/json/
            ;;
        "ip-api.com")
            curl -s http://ip-api.com/json/
            ;;
        *)
            curl -s https://ipinfo.io
            ;;
    esac
}

# Validate location data
validate_location() {
    local location_data="$1"
    
    # Check if data is valid JSON
    if ! echo "$location_data" | jq empty 2>/dev/null; then
        log_action "Invalid location data format"
        return 1
    fi
    
    # Check for required fields
    local ip city country
    ip=$(echo "$location_data" | jq -r '.ip // empty')
    city=$(echo "$location_data" | jq -r '.city // empty')
    country=$(echo "$location_data" | jq -r '.country // empty')
    
    if [[ -z "$ip" ]] || [[ -z "$city" ]] || [[ -z "$country" ]]; then
        log_action "Missing required location fields"
        return 1
    fi
    
    return 0
}

# Store location in database
store_location() {
    local location_data="$1"
    
    if ! validate_location "$location_data"; then
        return 1
    fi
    
    # Parse location data
    local timestamp ip city region country lat lon org timezone
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    ip=$(echo "$location_data" | jq -r '.ip')
    city=$(echo "$location_data" | jq -r '.city')
    region=$(echo "$location_data" | jq -r '.region // ""')
    country=$(echo "$location_data" | jq -r '.country')
    lat=$(echo "$location_data" | jq -r '.loc | split(",")[0] // ""')
    lon=$(echo "$location_data" | jq -r '.loc | split(",")[1] // ""')
    org=$(echo "$location_data" | jq -r '.org // ""')
    timezone=$(echo "$location_data" | jq -r '.timezone // ""')
    
    # Append to database
    echo "$timestamp,$ip,$city,$region,$country,$lat,$lon,$org,$timezone" >> "$LOCATION_DB"
    
    log_action "Location stored: $city, $region, $country"
}

# Check geofence compliance
check_geofence() {
    local location_data="$1"
    local country
    country=$(echo "$location_data" | jq -r '.country')
    
    if [[ "$GEOFENCE_ENABLED" == "true" ]]; then
        # Check if country is in allowed list
        local allowed=false
        for allowed_country in "${ALLOWED_COUNTRIES[@]}"; do
            if [[ "$country" == "$allowed_country" ]]; then
                allowed=true
                break
            fi
        done
        
        if [[ "$allowed" == "false" ]]; then
            log_action "ALERT: Device outside allowed geofence - Country: $country"
            send_security_alert "Geofence violation" "Device detected in unauthorized country: $country"
            return 1
        fi
    fi
    
    return 0
}

# Check for suspicious networks
check_network_security() {
    local location_data="$1"
    local org
    org=$(echo "$location_data" | jq -r '.org')
    
    # Check against blocked networks
    for blocked_network in "${BLOCKED_NETWORKS[@]}"; do
        if [[ "$org" == *"$blocked_network"* ]]; then
            log_action "SECURITY ALERT: Suspicious network detected - $org"
            send_security_alert "Suspicious Network" "Device connected via potentially risky network: $org"
            return 1
        fi
    done
    
    return 0
}

# Send security alerts
send_security_alert() {
    local alert_type="$1"
    local message="$2"
    local hostname
    hostname=$(hostname)
    
    # Log the alert
    log_action "SECURITY ALERT [$alert_type]: $message"
    
    # Send email alert (if configured)
    if command -v mail >/dev/null 2>&1 && [[ -n "$REPORT_EMAIL" ]]; then
        echo "Security Alert from Roundfleet Device: $hostname
        
Alert Type: $alert_type
Message: $message
Timestamp: $(date)
Device: $hostname

This is an automated security alert from Roundfleet Location Monitoring." | \
        mail -s "Roundfleet Security Alert: $alert_type" "$REPORT_EMAIL"
    fi
}

# Calculate distance between coordinates
calculate_distance() {
    local lat1="$1" lon1="$2" lat2="$3" lon2="$4"
    
    # Use python for more accurate calculation if available
    if command -v python3 >/dev/null 2>&1; then
        python3 -c "
import math
def haversine(lat1, lon1, lat2, lon2):
    R = 3959  # Earth's radius in miles
    dlat = math.radians(float(lat2) - float(lat1))
    dlon = math.radians(float(lon2) - float(lon1))
    a = math.sin(dlat/2)**2 + math.cos(math.radians(float(lat1))) * math.cos(math.radians(float(lat2))) * math.sin(dlon/2)**2
    c = 2 * math.asin(math.sqrt(a))
    return R * c
print(f'{haversine($lat1, $lon1, $lat2, $lon2):.2f}')
"
    else
        echo "0"
    fi
}

# Monitor location changes
monitor_location() {
    log_action "Starting location monitoring..."
    
    while true; do
        # Get current location
        local current_location
        current_location=$(get_location_info)
        
        if validate_location "$current_location"; then
            # Store location
            store_location "$current_location"
            
            # Security checks
            check_geofence "$current_location"
            check_network_security "$current_location"
            
            # Check for significant movement
            check_location_change "$current_location"
        else
            log_action "Failed to retrieve valid location data"
        fi
        
        sleep "$MONITORING_INTERVAL"
    done
}

# Check for significant location changes
check_location_change() {
    local current_location="$1"
    local last_location_file="/tmp/last_location.json"
    
    if [[ -f "$last_location_file" ]]; then
        local previous_location
        previous_location=$(cat "$last_location_file")
        
        # Get coordinates
        local curr_lat curr_lon prev_lat prev_lon
        curr_lat=$(echo "$current_location" | jq -r '.loc | split(",")[0] // ""')
        curr_lon=$(echo "$current_location" | jq -r '.loc | split(",")[1] // ""')
        prev_lat=$(echo "$previous_location" | jq -r '.loc | split(",")[0] // ""')
        prev_lon=$(echo "$previous_location" | jq -r '.loc | split(",")[1] // ""')
        
        if [[ -n "$curr_lat" && -n "$curr_lon" && -n "$prev_lat" && -n "$prev_lon" ]]; then
            local distance
            distance=$(calculate_distance "$prev_lat" "$prev_lon" "$curr_lat" "$curr_lon")
            
            if (( $(echo "$distance > $ALERT_THRESHOLD_MILES" | bc -l) )); then
                log_action "ALERT: Significant location change detected - Distance: ${distance} miles"
                send_security_alert "Location Change" "Device moved ${distance} miles from previous location"
            fi
        fi
    fi
    
    # Save current location
    echo "$current_location" > "$last_location_file"
}

# Generate location report
generate_location_report() {
    local report_file="/tmp/roundfleet_location_report_$(date +%Y%m%d_%H%M%S).txt"
    local hostname
    hostname=$(hostname)
    
    {
        echo "Roundfleet Device Location Report"
        echo "==============================="
        echo "Generated: $(date)"
        echo "Device: $hostname"
        echo ""
        
        echo "Current Location:"
        local current_location
        current_location=$(get_location_info)
        if validate_location "$current_location"; then
            echo "$current_location" | jq '.'
        else
            echo "Unable to retrieve current location"
        fi
        echo ""
        
        echo "Location History (Last 10 entries):"
        if [[ -f "$LOCATION_DB" ]]; then
            tail -10 "$LOCATION_DB" | column -t -s ','
        else
            echo "No location history available"
        fi
        echo ""
        
        echo "Security Events (Last 10):"
        if [[ -f "$LOG_FILE" ]]; then
            grep -i "alert\|security" "$LOG_FILE" | tail -10
        else
            echo "No security events logged"
        fi
        
    } > "$report_file"
    
    echo "πŸ“„ Location report generated: $report_file"
    log_action "Location report generated: $report_file"
}

# Main function
main() {
    case "${1:-status}" in
        "track")
            setup_environment
            load_config
            log_action "=== Location Tracking: Single Check ==="
            current_location=$(get_location_info)
            if validate_location "$current_location"; then
                store_location "$current_location"
                check_geofence "$current_location"
                check_network_security "$current_location"
                echo "$current_location" | jq '.'
            fi
            ;;
        "monitor")
            setup_environment
            load_config
            log_action "=== Location Monitoring: Continuous ==="
            monitor_location
            ;;
        "report")
            setup_environment
            load_config
            generate_location_report
            ;;
        "history")
            if [[ -f "$LOCATION_DB" ]]; then
                echo "πŸ“ Location History:"
                column -t -s ',' "$LOCATION_DB"
            else
                echo "No location history available"
            fi
            ;;
        "status"|*)
            setup_environment
            load_config
            echo "πŸ“Š Roundfleet Location Status:"
            echo "============================"
            current_location=$(get_location_info)
            if validate_location "$current_location"; then
                echo "$current_location" | jq '.'
            else
                echo "Unable to retrieve location information"
            fi
            ;;
    esac
}

# Execute main function with parameters
main "$@"

Location Tracking Commands

Quick Reference

TaskCommand
Get current locationcurl -s https://ipinfo.io
Formatted location infocurl -s https://ipinfo.io | jq '.'
Save location to filecurl -s https://ipinfo.io > location.json
Get specific fieldcurl -s https://ipinfo.io | jq -r '.city'

Location Data Fields

# Extract specific information
IP=$(curl -s https://ipinfo.io | jq -r '.ip')
CITY=$(curl -s https://ipinfo.io | jq -r '.city')
REGION=$(curl -s https://ipinfo.io | jq -r '.region')
COUNTRY=$(curl -s https://ipinfo.io | jq -r '.country')
COORDINATES=$(curl -s https://ipinfo.io | jq -r '.loc')
ORGANIZATION=$(curl -s https://ipinfo.io | jq -r '.org')
TIMEZONE=$(curl -s https://ipinfo.io | jq -r '.timezone')

Security and Compliance

Privacy Considerations

  1. Data Collection - Only collect necessary location data
  2. Storage Security - Encrypt location databases
  3. Access Control - Limit access to location information
  4. Retention Policy - Define data retention periods
  5. User Consent - Ensure proper authorization

Geofencing Implementation

#!/bin/bash

# Simple geofencing check
check_location_compliance() {
    local location_data
    location_data=$(curl -s https://ipinfo.io)
    
    local country
    country=$(echo "$location_data" | jq -r '.country')
    
    case "$country" in
        "US"|"CA"|"GB")
            echo "βœ… Location approved: $country"
            ;;
        *)
            echo "⚠️  Location outside approved regions: $country"
            # Log security event
            logger "Roundfleet: Device in unauthorized location: $country"
            ;;
    esac
}

Troubleshooting

Common Issues

  1. Network connectivity problems

    • Check internet connection
    • Verify firewall settings
    • Test alternative geolocation services
  2. Inaccurate location data

    • VPN/proxy connections affect accuracy
    • ISP location may not match physical location
    • Use multiple services for verification
  3. API rate limits

    • Implement proper delays between requests
    • Use authenticated API keys when available
    • Cache location data appropriately

Verification Commands

# Test network connectivity
ping -c 3 ipinfo.io

# Check if jq is installed
which jq || echo "jq not installed"

# Verify location service availability
curl -I https://ipinfo.io

Important Notes

  • Accuracy limitations: IP geolocation provides approximate location, not precise coordinates
  • Network dependencies: Requires internet connectivity to function
  • Privacy compliance: Ensure compliance with local privacy laws and regulations
  • VPN detection: Results may be affected by VPN or proxy services
  • Rate limiting: Implement appropriate delays to avoid service rate limits
  • Data storage: Securely store and manage collected location data

Enterprise Deployment

For enterprise deployment, consider:

  1. Policy definition - Establish clear location tracking policies
  2. Legal compliance - Ensure compliance with privacy regulations
  3. Security monitoring - Implement real-time location alerts
  4. Data governance - Define data retention and access policies
  5. User communication - Inform users about location tracking practices

Related Tutorials

Remote Ring and Device Location Management on macOS

Learn how to implement remote ring functionality, manage device location services, create audio alerts, and deploy enterprise device tracking solutions on macOS devices for fleet management.

Jul 7, 2025

Manage Location Services on macOS

Learn how to enable, disable, and monitor Location Services on macOS devices using command-line scripts for enhanced privacy and security management.

Jul 7, 2025

Time Machine Backup Management on macOS

Comprehensive guide to managing Time Machine backups across macOS fleets with enterprise policies, automated scheduling, disaster recovery, compliance monitoring, and fleet-wide deployment capabilities.

Jul 7, 2025

Fetch Device Logs on macOS

Learn how to collect system logs, application logs, and diagnostic information from macOS devices using the unified logging system for troubleshooting and monitoring.

Jul 7, 2025

Device Naming and Identity Management on macOS

Manage device names, hostnames, and network identities across Roundfleet devices with standardized naming conventions, automated provisioning, and enterprise compliance features.

Jul 7, 2025

Sharing User Management on macOS

Learn how to create and manage sharing-only user accounts on macOS devices using dscl commands with enterprise-grade security, bulk deployment, and fleet management capabilities.

Jul 7, 2025

User Creation Management on macOS

Comprehensive guide for enterprise user provisioning and lifecycle management on Roundfleet devices with automated workflows, security controls, and standardized user creation processes.

Jul 7, 2025

User Account Management on macOS

Learn how to create, manage, and configure user accounts on macOS devices using command-line tools. Comprehensive guide for admin and standard user creation, password policies, and enterprise user management.

Jul 7, 2025