(Note that the edits to the code in the question seem to make parts of this answer no longer quite correct.)
Per 6.2.2 Linkages of identifiers, paragraph 4 of the C standard:
For an identifier declared with the storage-class specifier extern
in a scope in which a prior declaration of that identifier is visible,
if the prior declaration specifies internal or external linkage, the
linkage of the identifier at the later declaration is the
same as the linkage specified at the prior declaration.
So, in your first two cases, the inner extern int a; has a prior declaration - a global int a; in your first case or extern int a; in your second case - so the extern int a; declaration refers to the global.
For the third case, the remainder of paragraph 4 is relevant:
If no prior declaration is visible, or if the prior
declaration specifies no linkage, then the identifier has external linkage.
Also, paragraph 6 states:
The following identifiers have no linkage: an identifier declared to be anything other than
an object or a function; an identifier declared to be a function parameter; a block scope
identifier for an object declared without the storage-class specifier
extern.
So the declaration in your third case is referring to an extern int a;
However, there is no actual int a; defined anywhere. And because the extern int a; in your third example appears in a block scope, and there is no actual definition of the int a; object elsewhere, your program fails to link.
Per 6.9.2 External object definitions, paragraph 2 states:
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier
static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
So the block-scope extern int a; declaration of your third case does not qualify as a tentative definition.