privoxy-log-parser: Update Privoxy man page reference now that the section is 8
[privoxy.git] / tools / uagen.pl
index d29ba90..b6af733 100755 (executable)
@@ -1,24 +1,23 @@
 #!/usr/bin/perl
 
 ##############################################################################################
 #!/usr/bin/perl
 
 ##############################################################################################
-# uagen (http://www.fabiankeil.de/sourcecode/uagen/)
-#
-# $Id: uagen.pl,v 1.62 2009/12/23 17:20:19 fk Exp fk $
+# uagen (https://www.fabiankeil.de/sourcecode/uagen/)
 #
 # Generates a pseudo-random Firefox user agent and writes it into a Privoxy action file
 # and optionally into a Mozilla prefs file. For documentation see 'perldoc uagen(.pl)'.
 #
 #
 # Generates a pseudo-random Firefox user agent and writes it into a Privoxy action file
 # and optionally into a Mozilla prefs file. For documentation see 'perldoc uagen(.pl)'.
 #
-# Examples (created with v1.0):
+# Examples (created with v1.2.2):
 #
 #
-# Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8.0.2) Gecko/20060421 Firefox/1.5.0.2
-# Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-CA; rv:1.8.0.2) Gecko/20060425 Firefox/1.5.0.2
-# Mozilla/5.0 (X11; U; SunOS i86pc; no-NO; rv:1.8.0.2) Gecko/20060420 Firefox/1.5.0.2
-# Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.8.0.2) Gecko/20060422 Firefox/1.5.0.2
-# Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8.0.2) Gecko/20060415 Firefox/1.5.0.2
-# Mozilla/5.0 (X11; U; OpenBSD sparc64; pl-PL; rv:1.8.0.2) Gecko/20060429 Firefox/1.5.0.2
-# Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.8.0.2) Gecko/20060413 Firefox/1.5.0.2
+# Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (Macintosh; PPC Mac OS X; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; NetBSD i386; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; OpenBSD alpha; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; FreeBSD amd64; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; ElectroBSD amd64; rv:78.0) Gecko/20100101 Firefox/78.0
+# Mozilla/5.0 (X11; FreeBSD i386; rv:78.0) Gecko/20100101 Firefox/78.0
 #
 #
-# Copyright (c) 2006-2009 Fabian Keil <fk@fabiankeil.de>
+# Copyright (c) 2006-2020 Fabian Keil <fk@fabiankeil.de>
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -40,7 +39,7 @@ use Getopt::Long;
 
 use constant {
 
 
 use constant {
 
-   UAGEN_VERSION       => 'uagen 1.0.10',
+   UAGEN_VERSION       => 'uagen 1.2.2',
 
    UAGEN_LOGFILE       => '/var/log/uagen.log',
    ACTION_FILE         => '/etc/privoxy/user-agent.action',
 
    UAGEN_LOGFILE       => '/var/log/uagen.log',
    ACTION_FILE         => '/etc/privoxy/user-agent.action',
@@ -51,14 +50,18 @@ use constant {
    LOOP                =>  0,
    SLEEPING_TIME       =>  5,
 
    LOOP                =>  0,
    SLEEPING_TIME       =>  5,
 
+   # As of Firefox 4, the "Gecko token" has been frozen
+   # https://hacks.mozilla.org/2010/09/final-user-agent-string-for-firefox-4/
+   RANDOMIZE_RELEASE_DATE => 0,
+
    # These variables belong together. If you only change one of them, the generated
    # User-Agent might be invalid. If you're not sure which values make sense,
    # are too lazy to check, but want to change them anyway, take the values you
    # see in the "Help/About Mozilla Firefox" menu.
 
    # These variables belong together. If you only change one of them, the generated
    # User-Agent might be invalid. If you're not sure which values make sense,
    # are too lazy to check, but want to change them anyway, take the values you
    # see in the "Help/About Mozilla Firefox" menu.
 
-   BROWSER_VERSION                   => "3.5.6",
-   BROWSER_REVISION                  => '1.9.1.6',
-   BROWSER_RELEASE_DATE              => '20091217',
+   BROWSER_VERSION                   => "78.0",
+   BROWSER_REVISION                  => '78.0',
+   BROWSER_RELEASE_DATE              => '20100101',
 };
 
 use constant LANGUAGES => qw(
 };
 
 use constant LANGUAGES => qw(
@@ -68,51 +71,48 @@ use constant LANGUAGES => qw(
 #######################################################################################
 
 sub generate_creation_time($) {
 #######################################################################################
 
 sub generate_creation_time($) {
-    my $release_date = $_ = shift;
+    my $release_date = shift;
 
     my ($rel_year, $rel_mon, $rel_day);
     my ($c_day, $c_mon, $c_year);
     my $now = time;
 
     my ($rel_year, $rel_mon, $rel_day);
     my ($c_day, $c_mon, $c_year);
     my $now = time;
-    my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
-       localtime $now;
+    my (undef, undef, undef, $mday, $mon, $year, undef, undef, undef) = localtime($now);
     $mon  += 1;
     $year += 1900;
 
     $mon  += 1;
     $year += 1900;
 
-    unless ( m/\d{6}/ ) {
+    unless ($release_date =~ m/\d{6}/) {
         log_error("Invalid release date format: $release_date. Using "
                   . BROWSER_RELEASE_DATE . " instead.");
         $release_date = BROWSER_RELEASE_DATE;
     }
         log_error("Invalid release date format: $release_date. Using "
                   . BROWSER_RELEASE_DATE . " instead.");
         $release_date = BROWSER_RELEASE_DATE;
     }
-    $rel_year = substr $release_date, 0, 4;
-    $rel_mon  = substr $release_date, 4, 2;
-    $rel_day  = substr $release_date, 6, 2;
+    $rel_year = substr($release_date, 0, 4);
+    $rel_mon  = substr($release_date, 4, 2);
+    $rel_day  = substr($release_date, 6, 2);
 
     #1, 2, 3, Check.
 
     #1, 2, 3, Check.
-    die "release year in the future" if ( $year < $rel_year );
+    die "release year in the future" if ($year < $rel_year);
     die "release month in the future"
     die "release month in the future"
-      if ( ( $year == $rel_year ) and ( $mon < $rel_mon ) );
+      if (($year == $rel_year) and ($mon < $rel_mon));
     die "release day in the future"
     die "release day in the future"
-      if (  ( $year == $rel_year )
-        and ( $mon  == $rel_mon )
-        and ( $mday  < $rel_day ) );    
+      if (($year == $rel_year) and ($mon == $rel_mon) and ($mday < $rel_day));
 
     my @c_time = (0, 0, 0, $rel_day, $rel_mon - 1, $rel_year - 1900, 0, 0, 0);
 
     my @c_time = (0, 0, 0, $rel_day, $rel_mon - 1, $rel_year - 1900, 0, 0, 0);
-    my $c_seconds = &timelocal( @c_time );
+    my $c_seconds = timelocal(@c_time);
 
 
-    $c_seconds = $now - (int rand ($now - $c_seconds)); 
-    @c_time = localtime $c_seconds;
-    ($sec, $min, $hour, $c_day, $c_mon, $c_year, $wday, $yday, $isdst) = @c_time;
+    $c_seconds = $now - (int rand ($now - $c_seconds));
+    @c_time = localtime($c_seconds);
+    (undef, undef, undef, $c_day, $c_mon, $c_year, undef, undef, undef) = @c_time;
     $c_mon  += 1;
     $c_year += 1900;
 
     #3, 2, 1, Test.
     $c_mon  += 1;
     $c_year += 1900;
 
     #3, 2, 1, Test.
-    die "Compilation year in the future" if ( $year < $c_year );
+    die "Compilation year in the future" if ($year < $c_year);
     die "Compilation month in the future"
     die "Compilation month in the future"
-      if ( ( $year == $c_year ) and ( $mon < $c_mon ) );
+      if (($year == $c_year) and ($mon < $c_mon));
     die "Compilation day in the future"
     die "Compilation day in the future"
-      if ( ( $year == $c_year ) and ( $mon == $c_mon ) and ( $mday < $c_day ) );
+      if (($year == $c_year) and ($mon == $c_mon) and ($mday < $c_day));
 
 
-    return sprintf "%.2i%.2i%.2i", $c_year, $c_mon, $c_day;
+    return sprintf("%.2i%.2i%.2i", $c_year, $c_mon, $c_day);
 }
 
 sub generate_language_settings() {
 }
 
 sub generate_language_settings() {
@@ -129,10 +129,16 @@ sub generate_language_settings() {
 sub generate_platform_and_os() {
 
     my %os_data = (
 sub generate_platform_and_os() {
 
     my %os_data = (
+        ElectroBSD => {
+            karma             => 1,
+            platform          => 'X11',
+            architectures     => [ 'i386', 'amd64' ],
+            order_is_inversed => 0,
+        },
         FreeBSD => {
             karma             => 1,
             platform          => 'X11',
         FreeBSD => {
             karma             => 1,
             platform          => 'X11',
-            architectures     => [ 'i386', 'amd64', 'sparc64', 'alpha' ],
+            architectures     => [ 'i386', 'amd64', 'sparc64' ],
             order_is_inversed => 0,
         },
         OpenBSD => {
             order_is_inversed => 0,
         },
         OpenBSD => {
@@ -200,17 +206,18 @@ sub generate_firefox_user_agent() {
     our $browser_version;
     our $browser_revision;
     our $browser_release_date;
     our $browser_version;
     our $browser_revision;
     our $browser_release_date;
+    our $randomize_release_date;
 
     my $mozillaversion  = '5.0';
 
     my $mozillaversion  = '5.0';
-    my $security        = "U";
 
 
-    my $creation_time = generate_creation_time($browser_release_date);
+    my $creation_time = $randomize_release_date ?
+        generate_creation_time($browser_release_date) : $browser_release_date;
     my ( $locale,   $accept_language ) = generate_language_settings();
     my ( $platform, $os_or_cpu )       = generate_platform_and_os;
 
     my $firefox_user_agent =
     my ( $locale,   $accept_language ) = generate_language_settings();
     my ( $platform, $os_or_cpu )       = generate_platform_and_os;
 
     my $firefox_user_agent =
-      sprintf "Mozilla/%s (%s; %s; %s; %s; rv:%s) Gecko/%s Firefox/%s",
-      $mozillaversion, $platform, $security, $os_or_cpu, $locale, $browser_revision,
+      sprintf "Mozilla/%s (%s; %s; rv:%s) Gecko/%s Firefox/%s",
+      $mozillaversion, $platform, $os_or_cpu, $browser_revision,
       $creation_time, $browser_version;
 
     return $accept_language, $firefox_user_agent;
       $creation_time, $browser_version;
 
     return $accept_language, $firefox_user_agent;
@@ -232,10 +239,9 @@ sub log_to_file($) {
 
     return if $no_logging;
 
 
     return if $no_logging;
 
-    open( LOGFILE, ">>" . $logfile ) || die "Writing " . $logfile . " failed";
-    printf LOGFILE UAGEN_VERSION . " ($logtime) $message\n";
-    close(LOGFILE);
-
+    open(my $log_fd, ">>", $logfile) || die "Writing " . $logfile . " failed";
+    printf $log_fd UAGEN_VERSION . " ($logtime) $message\n";
+    close($log_fd);
 }
 
 sub log_error($) {
 }
 
 sub log_error($) {
@@ -260,14 +266,14 @@ sub write_action_file() {
     my $action_file_content = '';
 
     if ($action_injection){
     my $action_file_content = '';
 
     if ($action_injection){
-        open( ACTIONFILE, $action_file )
+        open(my $actionfile_fd, "<", $action_file)
             or log_error "Reading action file $action_file failed!";
             or log_error "Reading action file $action_file failed!";
-        while (<ACTIONFILE>) {
+        while (<$actionfile_fd>) {
             s@(hide-accept-language\{).*?(\})@$1$accept_language$2@;
             s@(hide-user-agent\{).*?(\})@$1$user_agent$2@;
            $action_file_content .= $_;
         }
             s@(hide-accept-language\{).*?(\})@$1$accept_language$2@;
             s@(hide-user-agent\{).*?(\})@$1$user_agent$2@;
            $action_file_content .= $_;
         }
-        close (ACTIONFILE);
+        close($actionfile_fd);
     } else {
        $action_file_content = "{";
        $action_file_content .= sprintf "+hide-accept-language{%s} \\\n",
     } else {
        $action_file_content = "{";
        $action_file_content .= sprintf "+hide-accept-language{%s} \\\n",
@@ -275,10 +281,10 @@ sub write_action_file() {
         $action_file_content .= sprintf " +hide-user-agent{%s} \\\n}\n/\n",
             $user_agent;
     }
         $action_file_content .= sprintf " +hide-user-agent{%s} \\\n}\n/\n",
             $user_agent;
     }
-    open( ACTIONFILE, ">" . $action_file )
+    open(my $actionfile_fd, ">", $action_file)
       or log_error "Writing action file $action_file failed!";
       or log_error "Writing action file $action_file failed!";
-    print ACTIONFILE $action_file_content;
-    close(ACTIONFILE);
+    print $actionfile_fd $action_file_content;
+    close($actionfile_fd);
 
     return 0;
 }
 
     return 0;
 }
@@ -289,16 +295,18 @@ sub write_prefs_file() {
     our $user_agent;
     our $accept_language;
     our $clean_prefs;
     our $user_agent;
     our $accept_language;
     our $clean_prefs;
+
     my $prefs_file_content = '';
     my $prefs_file_content = '';
+    my $prefsfile_fd;
 
 
-    if (open( PREFSFILE, $mozilla_prefs_file )) {
+    if (open($prefsfile_fd, "<", $mozilla_prefs_file)) {
 
 
-        while (<PREFSFILE>) {
+        while (<$prefsfile_fd>) {
             s@user_pref\(\"general.useragent.override\",.*\);\n?@@;
             s@user_pref\(\"intl.accept_languages\",.*\);\n?@@;
            $prefs_file_content .= $_;
         }
             s@user_pref\(\"general.useragent.override\",.*\);\n?@@;
             s@user_pref\(\"intl.accept_languages\",.*\);\n?@@;
            $prefs_file_content .= $_;
         }
-        close (PREFSFILE);
+        close($prefsfile_fd);
     } else {
         log_error "Reading prefs file $mozilla_prefs_file failed. Creating a new file!";
     }
     } else {
         log_error "Reading prefs file $mozilla_prefs_file failed. Creating a new file!";
     }
@@ -308,16 +316,16 @@ sub write_prefs_file() {
         sprintf("user_pref(\"intl.accept_languages\", \"%s\");\n", $accept_language)
         unless $clean_prefs;
 
         sprintf("user_pref(\"intl.accept_languages\", \"%s\");\n", $accept_language)
         unless $clean_prefs;
 
-    open( PREFSFILE, ">" . $mozilla_prefs_file )
+    open($prefsfile_fd, ">", $mozilla_prefs_file)
       or log_error "Writing prefs file $mozilla_prefs_file failed!";
       or log_error "Writing prefs file $mozilla_prefs_file failed!";
-    print PREFSFILE $prefs_file_content;
-    close(PREFSFILE);
+    print $prefsfile_fd $prefs_file_content;
+    close($prefsfile_fd);
 
 }
 
 sub VersionMessage() {
 
 }
 
 sub VersionMessage() {
-    printf UAGEN_VERSION . "\n" . 'Copyright (C) 2006-2009 Fabian Keil <fk@fabiankeil.de> ' .
-        "\nhttp://www.fabiankeil.de/sourcecode/uagen/\n";
+    printf UAGEN_VERSION . "\n" . 'Copyright (C) 2006-2020 Fabian Keil <fk@fabiankeil.de> ' .
+        "\nhttps://www.fabiankeil.de/sourcecode/uagen/\n";
 }
 
 sub help() {
 }
 
 sub help() {
@@ -359,6 +367,7 @@ Options and their default values if there are any:
     [--no-hide-accept-language]
     [--no-logfile]
     [--prefs-file$mozilla_prefs_file]
     [--no-hide-accept-language]
     [--no-logfile]
     [--prefs-file$mozilla_prefs_file]
+    [--randomize-release-date]
     [--quiet]
     [--silent]
     [--sleeping-time $sleeping_time]
     [--quiet]
     [--silent]
     [--sleeping-time $sleeping_time]
@@ -378,6 +387,7 @@ sub main() {
     our $no_logging              = NO_LOGGING;
     our $logfile                 = UAGEN_LOGFILE;
     our $action_file             = ACTION_FILE;
     our $no_logging              = NO_LOGGING;
     our $logfile                 = UAGEN_LOGFILE;
     our $action_file             = ACTION_FILE;
+    our $randomize_release_date  = RANDOMIZE_RELEASE_DATE;
     our $browser_version         = BROWSER_VERSION;
     our $browser_revision        = BROWSER_REVISION;
     our $browser_release_date    = BROWSER_RELEASE_DATE;
     our $browser_version         = BROWSER_VERSION;
     our $browser_revision        = BROWSER_REVISION;
     our $browser_release_date    = BROWSER_RELEASE_DATE;
@@ -398,6 +408,7 @@ sub main() {
                'no-hide-accept-language' => \$no_hide_accept_language,
                'no-logfile' => \$no_logging,
                'no-action-file' => \$no_action_file,
                'no-hide-accept-language' => \$no_hide_accept_language,
                'no-logfile' => \$no_logging,
                'no-action-file' => \$no_action_file,
+               'randomize-release-date' => \$randomize_release_date,
                'browser-version=s' => \$browser_version,
                'browser-revision=s' => \$browser_revision,
                'browser-release-date=s' => \$browser_release_date,
                'browser-version=s' => \$browser_version,
                'browser-revision=s' => \$browser_revision,
                'browser-release-date=s' => \$browser_release_date,
@@ -433,7 +444,6 @@ sub main() {
 }
 
 main();
 }
 
 main();
-exit(0);
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -448,14 +458,14 @@ B<uagen> [B<--action-file> I<action_file>] [B<--action-injection>]
 [B<--clean-prefs-file>]
 [B<--help>] [B<--language-overwrite> I<language(s)>]
 [B<--logfile> I<logfile>] [B<--loop>] [B<--no-action-file>] [B<--no-logfile>]
 [B<--clean-prefs-file>]
 [B<--help>] [B<--language-overwrite> I<language(s)>]
 [B<--logfile> I<logfile>] [B<--loop>] [B<--no-action-file>] [B<--no-logfile>]
-[B<--prefs-file> I<prefs_file>]
+[B<--prefs-file> I<prefs_file>] [B<--randomize-release-date>]
 [B<--quiet>] [B<--sleeping-time> I<minutes>] [B<--silent>] [B<--version>]
 
 =head1 DESCRIPTION
 
 B<uagen> generates a fake Firefox User-Agent and writes it into a Privoxy action file
 as parameter for Privoxy's B<hide-user-agent> action. Operating system, architecture,
 [B<--quiet>] [B<--sleeping-time> I<minutes>] [B<--silent>] [B<--version>]
 
 =head1 DESCRIPTION
 
 B<uagen> generates a fake Firefox User-Agent and writes it into a Privoxy action file
 as parameter for Privoxy's B<hide-user-agent> action. Operating system, architecture,
-platform, language and build date are randomized.
+platform, language and, optionally, the build date are randomized.
 
 The generated language is also used as parameter for the
 B<hide-accept-language> action which is understood by Privoxy since
 
 The generated language is also used as parameter for the
 B<hide-accept-language> action which is understood by Privoxy since
@@ -475,10 +485,9 @@ to keep custom URL patterns. For this to work, the action file
 has to be already present. B<uagen> neither checks the syntax
 nor cares if all actions are present. Garbage in, garbage out.
 
 has to be already present. B<uagen> neither checks the syntax
 nor cares if all actions are present. Garbage in, garbage out.
 
-B<--browser-release-date> I<browser_release_date> Date when the faked
-browser version was first released, format is YYYYMMDD. B<uagen> will
-pick a date between the release date and the actual date to use it as
-build time. Some sanity checks are done, but you shouldn't rely on them.
+B<--browser-release-date> I<browser_release_date> Date to use.
+The format is YYYYMMDD. Some sanity checks are done, but you
+shouldn't rely on them.
 
 B<--browser-revision> I<browser_revision> Use a custom revision.
 B<uagen> will use it without any sanity checks.
 
 B<--browser-revision> I<browser_revision> Use a custom revision.
 B<uagen> will use it without any sanity checks.
@@ -520,13 +529,19 @@ Firefox's preference file is usually located in
 ~/.mozilla/firefox/*.default/prefs.js. Note that Firefox doesn't reread
 the file once it is running.
 
 ~/.mozilla/firefox/*.default/prefs.js. Note that Firefox doesn't reread
 the file once it is running.
 
+B<--randomize-release-date> Randomly pick a date between the configured
+release date and the actual date. Note that Firefox versions after 4.0
+no longer provide the build date in the User-Agent header, so if you
+randomize the date anyway, it will be obvious that the generated User-Agent
+is fake.
+
 B<--quiet> Don't print the generated User-Agent to the console.
 
 B<--sleeping-time> I<minutes> Time to sleep. Only effective if used with B<--loop>.
 
 B<--silent> Don't print the generated User-Agent to the console.
 
 B<--quiet> Don't print the generated User-Agent to the console.
 
 B<--sleeping-time> I<minutes> Time to sleep. Only effective if used with B<--loop>.
 
 B<--silent> Don't print the generated User-Agent to the console.
 
-B<--version> Print version and exit.  
+B<--version> Print version and exit.
 
 The second dash is optional, options can be shortened, as long as there are
 no ambiguities.
 
 The second dash is optional, options can be shortened, as long as there are
 no ambiguities.
@@ -569,10 +584,8 @@ could look like this one:
 
 =head1 CAVEATS
 
 
 =head1 CAVEATS
 
-If the browser opens an encrypted connection, Privoxy can't inspect
-the content and the browser's headers reach the server unmodified.
-It is the user's job to use Privoxy's limit-connect action to make sure
-there are no encrypted connections to untrusted sites.
+Use the https-inspection action to make sure Privoxy can modify
+the browser's headers for encrypted traffic as well.
 
 Mozilla users can alter the browser's User-Agent with the
 B<--prefs-file> option. But note that the preference file is only read
 
 Mozilla users can alter the browser's User-Agent with the
 B<--prefs-file> option. But note that the preference file is only read
@@ -594,9 +607,9 @@ privoxy(1)
 
 Fabian Keil <fk@fabiankeil.de>
 
 
 Fabian Keil <fk@fabiankeil.de>
 
-http://www.fabiankeil.de/sourcecode/uagen/
+https://www.fabiankeil.de/sourcecode/uagen/
 
 
-http://www.fabiankeil.de/blog-surrogat/2006/01/26/firefox-user-agent-generator.html (German)
+https://www.fabiankeil.de/blog-surrogat/2006/01/26/firefox-user-agent-generator.html (German)
 
 =cut
 
 
 =cut