##############################################################################################
# uagen (http://www.fabiankeil.de/sourcecode/uagen/)
#
-# $Id: uagen.pl,v 1.1 2009/12/24 12:57:34 fabiankeil Exp $
-#
# 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)'.
#
# 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
#
-# Copyright (c) 2006-2009 Fabian Keil <fk@fabiankeil.de>
+# Copyright (c) 2006-2011 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
use constant {
- UAGEN_VERSION => 'uagen 1.0.10',
+ UAGEN_VERSION => 'uagen 1.2.1',
UAGEN_LOGFILE => '/var/log/uagen.log',
ACTION_FILE => '/etc/privoxy/user-agent.action',
LOOP => 0,
SLEEPING_TIME => 5,
+ # As of Firefox 4, the "Gecko token" has been frozen
+ # http://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.
- BROWSER_VERSION => "3.5.6",
- BROWSER_REVISION => '1.9.1.6',
- BROWSER_RELEASE_DATE => '20091217',
+ BROWSER_VERSION => "17.0",
+ BROWSER_REVISION => '17.0',
+ BROWSER_RELEASE_DATE => '20100101',
};
use constant LANGUAGES => qw(
#######################################################################################
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 ( $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;
- 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;
}
- $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.
- 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"
- if ( ( $year == $rel_year ) and ( $mon < $rel_mon ) );
+ if (($year == $rel_year) and ($mon < $rel_mon));
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_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_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.
- 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"
- if ( ( $year == $c_year ) and ( $mon < $c_mon ) );
+ if (($year == $c_year) and ($mon < $c_mon));
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() {
FreeBSD => {
karma => 1,
platform => 'X11',
- architectures => [ 'i386', 'amd64', 'sparc64', 'alpha' ],
+ architectures => [ 'i386', 'amd64', 'sparc64' ],
order_is_inversed => 0,
},
OpenBSD => {
our $browser_version;
our $browser_revision;
our $browser_release_date;
+ our $randomize_release_date;
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 =
- 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;
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($) {
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!";
- while (<ACTIONFILE>) {
+ while (<$actionfile_fd>) {
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",
$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!";
- print ACTIONFILE $action_file_content;
- close(ACTIONFILE);
+ print $actionfile_fd $action_file_content;
+ close($actionfile_fd);
return 0;
}
our $user_agent;
our $accept_language;
our $clean_prefs;
+
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 .= $_;
}
- close (PREFSFILE);
+ close($prefsfile_fd);
} else {
log_error "Reading prefs file $mozilla_prefs_file failed. Creating a new file!";
}
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!";
- print PREFSFILE $prefs_file_content;
- close(PREFSFILE);
+ print $prefsfile_fd $prefs_file_content;
+ close($prefsfile_fd);
}
sub VersionMessage() {
- printf UAGEN_VERSION . "\n" . 'Copyright (C) 2006-2009 Fabian Keil <fk@fabiankeil.de> ' .
+ printf UAGEN_VERSION . "\n" . 'Copyright (C) 2006-2011 Fabian Keil <fk@fabiankeil.de> ' .
"\nhttp://www.fabiankeil.de/sourcecode/uagen/\n";
}
[--no-hide-accept-language]
[--no-logfile]
[--prefs-file$mozilla_prefs_file]
+ [--randomize-release-date]
[--quiet]
[--silent]
[--sleeping-time $sleeping_time]
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;
'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,
}
main();
-exit(0);
=head1 NAME
[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,
-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
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.
~/.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>.